@needle-tools/engine 5.1.0-alpha.3 → 5.1.0-alpha.5
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/CHANGELOG.md +68 -0
- package/SKILL.md +4 -1
- package/components.needle.json +1 -1
- package/dist/{needle-engine.bundle-DF01sSGQ.js → needle-engine.bundle-C-LG00ZZ.js} +10681 -10100
- package/dist/needle-engine.bundle-D7tzaiYE.min.js +1733 -0
- package/dist/{needle-engine.bundle-C-ixARur.umd.cjs → needle-engine.bundle-OPkPmdUM.umd.cjs} +161 -161
- package/dist/needle-engine.d.ts +1349 -317
- package/dist/needle-engine.js +556 -555
- package/dist/needle-engine.min.js +1 -1
- package/dist/needle-engine.umd.cjs +1 -1
- package/dist/three.js +1 -0
- package/dist/three.min.js +21 -21
- package/dist/three.umd.cjs +16 -16
- package/lib/engine/api.d.ts +5 -0
- package/lib/engine/api.js +4 -0
- package/lib/engine/api.js.map +1 -1
- package/lib/engine/codegen/register_types.js +10 -18
- package/lib/engine/codegen/register_types.js.map +1 -1
- package/lib/engine/engine_camera.fit.js +16 -4
- package/lib/engine/engine_camera.fit.js.map +1 -1
- package/lib/engine/engine_context.d.ts +20 -7
- package/lib/engine/engine_context.js +31 -15
- package/lib/engine/engine_context.js.map +1 -1
- package/lib/engine/engine_context_eventbus.d.ts +47 -0
- package/lib/engine/engine_context_eventbus.js +47 -0
- package/lib/engine/engine_context_eventbus.js.map +1 -0
- package/lib/engine/engine_disposable.d.ts +172 -0
- package/lib/engine/engine_disposable.js +136 -0
- package/lib/engine/engine_disposable.js.map +1 -0
- package/lib/engine/engine_gameobject.d.ts +1 -10
- package/lib/engine/engine_gameobject.js +20 -118
- package/lib/engine/engine_gameobject.js.map +1 -1
- package/lib/engine/engine_gltf_builtin_components.js +7 -69
- package/lib/engine/engine_gltf_builtin_components.js.map +1 -1
- package/lib/engine/engine_input.d.ts +23 -4
- package/lib/engine/engine_input.js +2 -1
- package/lib/engine/engine_input.js.map +1 -1
- package/lib/engine/engine_instantiate_resolve.d.ts +42 -0
- package/lib/engine/engine_instantiate_resolve.js +372 -0
- package/lib/engine/engine_instantiate_resolve.js.map +1 -0
- package/lib/engine/engine_mainloop_utils.js +2 -2
- package/lib/engine/engine_mainloop_utils.js.map +1 -1
- package/lib/engine/engine_networking.d.ts +51 -37
- package/lib/engine/engine_networking.js +132 -82
- package/lib/engine/engine_networking.js.map +1 -1
- package/lib/engine/engine_networking.transport.websocket.d.ts +15 -0
- package/lib/engine/engine_networking.transport.websocket.js +38 -0
- package/lib/engine/engine_networking.transport.websocket.js.map +1 -0
- package/lib/engine/engine_networking_instantiate.js +2 -2
- package/lib/engine/engine_networking_instantiate.js.map +1 -1
- package/lib/engine/engine_networking_types.d.ts +39 -1
- package/lib/engine/engine_networking_types.js +7 -0
- package/lib/engine/engine_networking_types.js.map +1 -1
- package/lib/engine/engine_physics_rapier.d.ts +21 -3
- package/lib/engine/engine_physics_rapier.js +94 -25
- package/lib/engine/engine_physics_rapier.js.map +1 -1
- package/lib/engine/engine_serialization_builtin_serializer.js +1 -5
- package/lib/engine/engine_serialization_builtin_serializer.js.map +1 -1
- package/lib/engine/engine_serialization_core.d.ts +1 -0
- package/lib/engine/engine_serialization_core.js +7 -0
- package/lib/engine/engine_serialization_core.js.map +1 -1
- package/lib/engine/engine_types.d.ts +29 -11
- package/lib/engine/engine_types.js +1 -1
- package/lib/engine/engine_types.js.map +1 -1
- package/lib/engine/engine_util_decorator.js +7 -2
- package/lib/engine/engine_util_decorator.js.map +1 -1
- package/lib/engine/engine_utils.d.ts +1 -1
- package/lib/engine/engine_utils.js +19 -5
- package/lib/engine/engine_utils.js.map +1 -1
- package/lib/engine-components/AnimationBuilder.d.ts +158 -0
- package/lib/engine-components/AnimationBuilder.js +305 -0
- package/lib/engine-components/AnimationBuilder.js.map +1 -0
- package/lib/engine-components/Animator.d.ts +6 -0
- package/lib/engine-components/Animator.js +23 -13
- package/lib/engine-components/Animator.js.map +1 -1
- package/lib/engine-components/AnimatorController.builder.d.ts +191 -0
- package/lib/engine-components/AnimatorController.builder.js +263 -0
- package/lib/engine-components/AnimatorController.builder.js.map +1 -0
- package/lib/engine-components/AnimatorController.d.ts +2 -119
- package/lib/engine-components/AnimatorController.js +33 -232
- package/lib/engine-components/AnimatorController.js.map +1 -1
- package/lib/engine-components/Collider.d.ts +18 -9
- package/lib/engine-components/Collider.js +61 -14
- package/lib/engine-components/Collider.js.map +1 -1
- package/lib/engine-components/Component.d.ts +72 -9
- package/lib/engine-components/Component.js +114 -10
- package/lib/engine-components/Component.js.map +1 -1
- package/lib/engine-components/ContactShadows.d.ts +1 -0
- package/lib/engine-components/ContactShadows.js +14 -1
- package/lib/engine-components/ContactShadows.js.map +1 -1
- package/lib/engine-components/DragControls.js +0 -7
- package/lib/engine-components/DragControls.js.map +1 -1
- package/lib/engine-components/DropListener.js +3 -0
- package/lib/engine-components/DropListener.js.map +1 -1
- package/lib/engine-components/EventList.d.ts +31 -9
- package/lib/engine-components/EventList.js +37 -76
- package/lib/engine-components/EventList.js.map +1 -1
- package/lib/engine-components/Joints.d.ts +4 -2
- package/lib/engine-components/Joints.js +19 -3
- package/lib/engine-components/Joints.js.map +1 -1
- package/lib/engine-components/Light.js +9 -1
- package/lib/engine-components/Light.js.map +1 -1
- package/lib/engine-components/OrbitControls.d.ts +0 -2
- package/lib/engine-components/OrbitControls.js +14 -1
- package/lib/engine-components/OrbitControls.js.map +1 -1
- package/lib/engine-components/RigidBody.d.ts +12 -4
- package/lib/engine-components/RigidBody.js +18 -4
- package/lib/engine-components/RigidBody.js.map +1 -1
- package/lib/engine-components/SceneSwitcher.js +3 -0
- package/lib/engine-components/SceneSwitcher.js.map +1 -1
- package/lib/engine-components/api.d.ts +2 -1
- package/lib/engine-components/api.js +2 -1
- package/lib/engine-components/api.js.map +1 -1
- package/lib/engine-components/codegen/components.d.ts +7 -13
- package/lib/engine-components/codegen/components.js +7 -13
- package/lib/engine-components/codegen/components.js.map +1 -1
- package/lib/engine-components/postprocessing/Effects/Tonemapping.utils.d.ts +1 -1
- package/lib/engine-components/timeline/PlayableDirector.d.ts +21 -11
- package/lib/engine-components/timeline/PlayableDirector.js +75 -67
- package/lib/engine-components/timeline/PlayableDirector.js.map +1 -1
- package/lib/engine-components/timeline/SignalAsset.d.ts +3 -1
- package/lib/engine-components/timeline/SignalAsset.js +1 -0
- package/lib/engine-components/timeline/SignalAsset.js.map +1 -1
- package/lib/engine-components/timeline/TimelineBuilder.d.ts +413 -0
- package/lib/engine-components/timeline/TimelineBuilder.js +506 -0
- package/lib/engine-components/timeline/TimelineBuilder.js.map +1 -0
- package/lib/engine-components/timeline/TimelineModels.d.ts +2 -1
- package/lib/engine-components/timeline/TimelineModels.js +3 -0
- package/lib/engine-components/timeline/TimelineModels.js.map +1 -1
- package/lib/engine-components/timeline/TimelineTracks.d.ts +37 -6
- package/lib/engine-components/timeline/TimelineTracks.js +92 -26
- package/lib/engine-components/timeline/TimelineTracks.js.map +1 -1
- package/lib/engine-components/timeline/index.d.ts +2 -1
- package/lib/engine-components/timeline/index.js +2 -0
- package/lib/engine-components/timeline/index.js.map +1 -1
- package/lib/engine-components/web/CursorFollow.d.ts +0 -1
- package/lib/engine-components/web/CursorFollow.js +0 -1
- package/lib/engine-components/web/CursorFollow.js.map +1 -1
- package/package.json +2 -83
- package/plugins/common/cloud.js +6 -1
- package/plugins/common/license.js +5 -2
- package/plugins/common/worker.js +9 -4
- package/plugins/vite/dependencies.js +1 -11
- package/plugins/vite/dependency-watcher.js +2 -2
- package/plugins/vite/editor-connection.js +3 -3
- package/plugins/vite/license.js +19 -1
- package/plugins/vite/reload.js +1 -1
- package/plugins/vite/server.js +2 -1
- package/src/engine/api.ts +7 -0
- package/src/engine/codegen/register_types.ts +10 -18
- package/src/engine/engine_camera.fit.ts +15 -4
- package/src/engine/engine_context.ts +32 -16
- package/src/engine/engine_context_eventbus.ts +73 -0
- package/src/engine/engine_disposable.ts +214 -0
- package/src/engine/engine_gameobject.ts +52 -157
- package/src/engine/engine_gltf_builtin_components.ts +7 -76
- package/src/engine/engine_input.ts +27 -6
- package/src/engine/engine_instantiate_resolve.ts +407 -0
- package/src/engine/engine_mainloop_utils.ts +2 -2
- package/src/engine/engine_networking.transport.websocket.ts +45 -0
- package/src/engine/engine_networking.ts +161 -137
- package/src/engine/engine_networking_instantiate.ts +2 -2
- package/src/engine/engine_networking_types.ts +41 -1
- package/src/engine/engine_physics_rapier.ts +102 -33
- package/src/engine/engine_serialization_builtin_serializer.ts +1 -6
- package/src/engine/engine_serialization_core.ts +9 -0
- package/src/engine/engine_types.ts +46 -27
- package/src/engine/engine_util_decorator.ts +7 -2
- package/src/engine/engine_utils.ts +16 -5
- package/src/engine-components/AnimationBuilder.ts +472 -0
- package/src/engine-components/Animator.ts +24 -12
- package/src/engine-components/AnimatorController.builder.ts +387 -0
- package/src/engine-components/AnimatorController.ts +20 -291
- package/src/engine-components/Collider.ts +66 -18
- package/src/engine-components/Component.ts +118 -20
- package/src/engine-components/ContactShadows.ts +15 -1
- package/src/engine-components/DragControls.ts +0 -9
- package/src/engine-components/DropListener.ts +3 -0
- package/src/engine-components/EventList.ts +45 -83
- package/src/engine-components/Joints.ts +20 -4
- package/src/engine-components/Light.ts +10 -2
- package/src/engine-components/OrbitControls.ts +16 -5
- package/src/engine-components/RigidBody.ts +18 -4
- package/src/engine-components/SceneSwitcher.ts +3 -0
- package/src/engine-components/api.ts +2 -1
- package/src/engine-components/codegen/components.ts +7 -13
- package/src/engine-components/timeline/PlayableDirector.ts +83 -81
- package/src/engine-components/timeline/SignalAsset.ts +4 -1
- package/src/engine-components/timeline/TimelineBuilder.ts +824 -0
- package/src/engine-components/timeline/TimelineModels.ts +5 -1
- package/src/engine-components/timeline/TimelineTracks.ts +96 -27
- package/src/engine-components/timeline/index.ts +2 -1
- package/src/engine-components/web/CursorFollow.ts +0 -1
- package/dist/needle-engine.bundle-CHmXdnE1.min.js +0 -1733
- package/lib/engine-components/AvatarLoader.d.ts +0 -80
- package/lib/engine-components/AvatarLoader.js +0 -232
- package/lib/engine-components/AvatarLoader.js.map +0 -1
- package/lib/engine-components/avatar/AvatarBlink_Simple.d.ts +0 -11
- package/lib/engine-components/avatar/AvatarBlink_Simple.js +0 -77
- package/lib/engine-components/avatar/AvatarBlink_Simple.js.map +0 -1
- package/lib/engine-components/avatar/AvatarEyeLook_Rotation.d.ts +0 -14
- package/lib/engine-components/avatar/AvatarEyeLook_Rotation.js +0 -69
- package/lib/engine-components/avatar/AvatarEyeLook_Rotation.js.map +0 -1
- package/lib/engine-components/avatar/Avatar_Brain_LookAt.d.ts +0 -29
- package/lib/engine-components/avatar/Avatar_Brain_LookAt.js +0 -122
- package/lib/engine-components/avatar/Avatar_Brain_LookAt.js.map +0 -1
- package/lib/engine-components/avatar/Avatar_MouthShapes.d.ts +0 -15
- package/lib/engine-components/avatar/Avatar_MouthShapes.js +0 -80
- package/lib/engine-components/avatar/Avatar_MouthShapes.js.map +0 -1
- package/lib/engine-components/avatar/Avatar_MustacheShake.d.ts +0 -9
- package/lib/engine-components/avatar/Avatar_MustacheShake.js +0 -30
- package/lib/engine-components/avatar/Avatar_MustacheShake.js.map +0 -1
- package/src/engine-components/AvatarLoader.ts +0 -264
- package/src/engine-components/avatar/AvatarBlink_Simple.ts +0 -70
- package/src/engine-components/avatar/AvatarEyeLook_Rotation.ts +0 -64
- package/src/engine-components/avatar/Avatar_Brain_LookAt.ts +0 -140
- package/src/engine-components/avatar/Avatar_MouthShapes.ts +0 -84
- package/src/engine-components/avatar/Avatar_MustacheShake.ts +0 -32
|
@@ -5,6 +5,7 @@ import { AnimationUtils } from "../engine/engine_animation.js";
|
|
|
5
5
|
import { Mathf } from "../engine/engine_math.js";
|
|
6
6
|
import { InstantiateIdProvider } from "../engine/engine_networking_instantiate.js";
|
|
7
7
|
import { assign, SerializationContext, TypeSerializer } from "../engine/engine_serialization_core.js";
|
|
8
|
+
import { serializable } from "../engine/engine_serialization_decorator.js";
|
|
8
9
|
import { Context } from "../engine/engine_setup.js";
|
|
9
10
|
import { isAnimationAction } from "../engine/engine_three_utils.js";
|
|
10
11
|
import { TypeStore } from "../engine/engine_typestore.js";
|
|
@@ -12,6 +13,9 @@ import { deepClone, getParam } from "../engine/engine_utils.js";
|
|
|
12
13
|
import type { AnimatorControllerModel, Condition, Parameter, State, Transition } from "../engine/extensions/NEEDLE_animator_controller_model.js";
|
|
13
14
|
import { AnimatorConditionMode, AnimatorControllerParameterType, AnimatorStateInfo, createMotion, StateMachineBehaviour } from "../engine/extensions/NEEDLE_animator_controller_model.js";
|
|
14
15
|
import type { Animator } from "./Animator.js";
|
|
16
|
+
import { AnimatorControllerBuilder } from "./AnimatorController.builder.js";
|
|
17
|
+
|
|
18
|
+
export { AnimatorControllerBuilder, type ConditionMode, type StateOptions, type TransitionOptions } from "./AnimatorController.builder.js";
|
|
15
19
|
|
|
16
20
|
const debug = getParam("debuganimatorcontroller");
|
|
17
21
|
const debugRootMotion = getParam("debugrootmotion");
|
|
@@ -30,263 +34,6 @@ declare type CreateAnimatorControllerOptions = {
|
|
|
30
34
|
}
|
|
31
35
|
|
|
32
36
|
|
|
33
|
-
// #region AnimatorControllerBuilder
|
|
34
|
-
|
|
35
|
-
/**
|
|
36
|
-
* Configuration for an animation state in the builder
|
|
37
|
-
*/
|
|
38
|
-
export declare type StateOptions = {
|
|
39
|
-
/** The animation clip for this state */
|
|
40
|
-
clip: AnimationClip;
|
|
41
|
-
/** Whether the animation should loop (default: false) */
|
|
42
|
-
loop?: boolean;
|
|
43
|
-
/** Base speed multiplier (default: 1) */
|
|
44
|
-
speed?: number;
|
|
45
|
-
/** Name of a float parameter to multiply with speed */
|
|
46
|
-
speedParameter?: string;
|
|
47
|
-
/** Normalized cycle offset 0-1 (default: 0) */
|
|
48
|
-
cycleOffset?: number;
|
|
49
|
-
/** Name of a float parameter to use as cycle offset */
|
|
50
|
-
cycleOffsetParameter?: string;
|
|
51
|
-
}
|
|
52
|
-
|
|
53
|
-
/**
|
|
54
|
-
* Configuration for a transition in the builder
|
|
55
|
-
*/
|
|
56
|
-
export declare type TransitionOptions = {
|
|
57
|
-
/** Duration of the crossfade in seconds (default: 0) */
|
|
58
|
-
duration?: number;
|
|
59
|
-
/** Normalized exit time 0-1 (default: 1). Only used when hasExitTime is true */
|
|
60
|
-
exitTime?: number;
|
|
61
|
-
/** Whether the transition waits for exitTime before transitioning (default: false) */
|
|
62
|
-
hasExitTime?: boolean;
|
|
63
|
-
/** Normalized offset into the destination state's animation (default: 0) */
|
|
64
|
-
offset?: number;
|
|
65
|
-
/** Whether duration is in seconds (true) or normalized (false) (default: false) */
|
|
66
|
-
hasFixedDuration?: boolean;
|
|
67
|
-
}
|
|
68
|
-
|
|
69
|
-
/** String condition modes for the builder, mapped to {@link AnimatorConditionMode} */
|
|
70
|
-
export type ConditionMode = "if" | "ifNot" | "greater" | "less" | "equals" | "notEqual";
|
|
71
|
-
|
|
72
|
-
function conditionModeToEnum(mode: ConditionMode): AnimatorConditionMode {
|
|
73
|
-
switch (mode) {
|
|
74
|
-
case "if": return AnimatorConditionMode.If;
|
|
75
|
-
case "ifNot": return AnimatorConditionMode.IfNot;
|
|
76
|
-
case "greater": return AnimatorConditionMode.Greater;
|
|
77
|
-
case "less": return AnimatorConditionMode.Less;
|
|
78
|
-
case "equals": return AnimatorConditionMode.Equals;
|
|
79
|
-
case "notEqual": return AnimatorConditionMode.NotEqual;
|
|
80
|
-
}
|
|
81
|
-
}
|
|
82
|
-
|
|
83
|
-
type BuilderTransition = {
|
|
84
|
-
to: string;
|
|
85
|
-
options: TransitionOptions;
|
|
86
|
-
conditions: Array<{ parameter: string; mode: ConditionMode; threshold: number }>;
|
|
87
|
-
};
|
|
88
|
-
|
|
89
|
-
type BuilderState = {
|
|
90
|
-
name: string;
|
|
91
|
-
options: StateOptions;
|
|
92
|
-
transitions: BuilderTransition[];
|
|
93
|
-
};
|
|
94
|
-
|
|
95
|
-
/**
|
|
96
|
-
* A fluent builder for creating {@link AnimatorController} instances from code.
|
|
97
|
-
*
|
|
98
|
-
* Use {@link AnimatorController.build} to create a new builder.
|
|
99
|
-
*
|
|
100
|
-
* @example
|
|
101
|
-
* ```ts
|
|
102
|
-
* const controller = AnimatorController.build("CharacterController")
|
|
103
|
-
* .floatParameter("Speed", 0)
|
|
104
|
-
* .triggerParameter("Jump")
|
|
105
|
-
* .state("Idle", { clip: idleClip, loop: true })
|
|
106
|
-
* .state("Walk", { clip: walkClip, loop: true })
|
|
107
|
-
* .state("Jump", { clip: jumpClip })
|
|
108
|
-
* .transition("Idle", "Walk", { duration: 0.25 })
|
|
109
|
-
* .condition("Speed", "greater", 0.1)
|
|
110
|
-
* .transition("Walk", "Idle", { duration: 0.25 })
|
|
111
|
-
* .condition("Speed", "less", 0.1)
|
|
112
|
-
* .transition("*", "Jump", { duration: 0.1 })
|
|
113
|
-
* .condition("Jump", "if")
|
|
114
|
-
* .transition("Jump", "Idle", { hasExitTime: true, exitTime: 0.9, duration: 0.25 })
|
|
115
|
-
* .build();
|
|
116
|
-
* ```
|
|
117
|
-
*
|
|
118
|
-
* @category Animation and Sequencing
|
|
119
|
-
* @group Utilities
|
|
120
|
-
*/
|
|
121
|
-
export class AnimatorControllerBuilder {
|
|
122
|
-
private _name: string;
|
|
123
|
-
private _parameters: Parameter[] = [];
|
|
124
|
-
private _states: BuilderState[] = [];
|
|
125
|
-
private _anyStateTransitions: BuilderTransition[] = [];
|
|
126
|
-
private _defaultStateName: string | null = null;
|
|
127
|
-
private _lastTransition: BuilderTransition | null = null;
|
|
128
|
-
|
|
129
|
-
constructor(name?: string) {
|
|
130
|
-
this._name = name ?? "AnimatorController";
|
|
131
|
-
}
|
|
132
|
-
|
|
133
|
-
/** Adds a float parameter */
|
|
134
|
-
floatParameter(name: string, defaultValue: number = 0): this {
|
|
135
|
-
this._parameters.push({ name, hash: this._parameters.length, type: AnimatorControllerParameterType.Float, value: defaultValue });
|
|
136
|
-
return this;
|
|
137
|
-
}
|
|
138
|
-
|
|
139
|
-
/** Adds an integer parameter */
|
|
140
|
-
intParameter(name: string, defaultValue: number = 0): this {
|
|
141
|
-
this._parameters.push({ name, hash: this._parameters.length, type: AnimatorControllerParameterType.Int, value: defaultValue });
|
|
142
|
-
return this;
|
|
143
|
-
}
|
|
144
|
-
|
|
145
|
-
/** Adds a boolean parameter */
|
|
146
|
-
boolParameter(name: string, defaultValue: boolean = false): this {
|
|
147
|
-
this._parameters.push({ name, hash: this._parameters.length, type: AnimatorControllerParameterType.Bool, value: defaultValue });
|
|
148
|
-
return this;
|
|
149
|
-
}
|
|
150
|
-
|
|
151
|
-
/** Adds a trigger parameter */
|
|
152
|
-
triggerParameter(name: string): this {
|
|
153
|
-
this._parameters.push({ name, hash: this._parameters.length, type: AnimatorControllerParameterType.Trigger, value: false });
|
|
154
|
-
return this;
|
|
155
|
-
}
|
|
156
|
-
|
|
157
|
-
/**
|
|
158
|
-
* Adds a state to the controller. The first state added becomes the default state.
|
|
159
|
-
* @param name - Unique name for the state
|
|
160
|
-
* @param options - State configuration including clip, loop, speed
|
|
161
|
-
*/
|
|
162
|
-
state(name: string, options: StateOptions): this {
|
|
163
|
-
this._states.push({ name, options, transitions: [] });
|
|
164
|
-
return this;
|
|
165
|
-
}
|
|
166
|
-
|
|
167
|
-
/**
|
|
168
|
-
* Adds a transition between two states.
|
|
169
|
-
* Use `"*"` as the source to create a transition from any state.
|
|
170
|
-
* Chain `.condition()` calls after this to add conditions.
|
|
171
|
-
* @param from - Source state name, or `"*"` for any-state transition
|
|
172
|
-
* @param to - Destination state name
|
|
173
|
-
* @param options - Transition configuration
|
|
174
|
-
*/
|
|
175
|
-
transition(from: string, to: string, options?: TransitionOptions): this {
|
|
176
|
-
const t: BuilderTransition = { to, options: options ?? {}, conditions: [] };
|
|
177
|
-
if (from === "*") {
|
|
178
|
-
this._anyStateTransitions.push(t);
|
|
179
|
-
}
|
|
180
|
-
else {
|
|
181
|
-
const state = this._states.find(s => s.name === from);
|
|
182
|
-
if (!state) throw new Error(`AnimatorControllerBuilder: source state "${from}" not found. Add it with .state() first.`);
|
|
183
|
-
state.transitions.push(t);
|
|
184
|
-
}
|
|
185
|
-
this._lastTransition = t;
|
|
186
|
-
return this;
|
|
187
|
-
}
|
|
188
|
-
|
|
189
|
-
/**
|
|
190
|
-
* Adds a condition to the most recently added transition.
|
|
191
|
-
* Multiple conditions on the same transition are AND-ed together.
|
|
192
|
-
* @param parameter - Name of the parameter to evaluate
|
|
193
|
-
* @param mode - Condition mode: `"if"`, `"ifNot"`, `"greater"`, `"less"`, `"equals"`, `"notEqual"`
|
|
194
|
-
* @param threshold - Comparison threshold for numeric conditions (default: 0)
|
|
195
|
-
*/
|
|
196
|
-
condition(parameter: string, mode: ConditionMode, threshold: number = 0): this {
|
|
197
|
-
if (!this._lastTransition) throw new Error("AnimatorControllerBuilder: .condition() must be called after .transition()");
|
|
198
|
-
this._lastTransition.conditions.push({ parameter, mode, threshold });
|
|
199
|
-
return this;
|
|
200
|
-
}
|
|
201
|
-
|
|
202
|
-
/**
|
|
203
|
-
* Sets which state is the default/entry state.
|
|
204
|
-
* If not called, the first added state is used.
|
|
205
|
-
* @param name - Name of the state
|
|
206
|
-
*/
|
|
207
|
-
defaultState(name: string): this {
|
|
208
|
-
this._defaultStateName = name;
|
|
209
|
-
return this;
|
|
210
|
-
}
|
|
211
|
-
|
|
212
|
-
/**
|
|
213
|
-
* Builds and returns the {@link AnimatorController}.
|
|
214
|
-
* Resolves all state name references to indices.
|
|
215
|
-
*/
|
|
216
|
-
build(): AnimatorController {
|
|
217
|
-
const stateIndexMap = new Map<string, number>();
|
|
218
|
-
this._states.forEach((s, i) => stateIndexMap.set(s.name, i));
|
|
219
|
-
|
|
220
|
-
let defaultStateIndex = 0;
|
|
221
|
-
if (this._defaultStateName !== null) {
|
|
222
|
-
const idx = stateIndexMap.get(this._defaultStateName);
|
|
223
|
-
if (idx === undefined) throw new Error(`AnimatorControllerBuilder: default state "${this._defaultStateName}" not found`);
|
|
224
|
-
defaultStateIndex = idx;
|
|
225
|
-
}
|
|
226
|
-
|
|
227
|
-
const resolveTransition = (t: BuilderTransition): Transition => {
|
|
228
|
-
const destIndex = stateIndexMap.get(t.to);
|
|
229
|
-
if (destIndex === undefined) throw new Error(`AnimatorControllerBuilder: transition target "${t.to}" not found`);
|
|
230
|
-
return {
|
|
231
|
-
exitTime: t.options.exitTime ?? 1,
|
|
232
|
-
hasExitTime: t.options.hasExitTime ?? false,
|
|
233
|
-
duration: t.options.duration ?? 0,
|
|
234
|
-
offset: t.options.offset ?? 0,
|
|
235
|
-
hasFixedDuration: t.options.hasFixedDuration ?? false,
|
|
236
|
-
destinationState: destIndex,
|
|
237
|
-
conditions: t.conditions.map(c => ({
|
|
238
|
-
parameter: c.parameter,
|
|
239
|
-
mode: conditionModeToEnum(c.mode),
|
|
240
|
-
threshold: c.threshold,
|
|
241
|
-
})),
|
|
242
|
-
};
|
|
243
|
-
};
|
|
244
|
-
|
|
245
|
-
const states: State[] = this._states.map((s, index) => {
|
|
246
|
-
const transitions: Transition[] = s.transitions.map(resolveTransition);
|
|
247
|
-
|
|
248
|
-
// Replicate any-state transitions onto every state (except self-targeting)
|
|
249
|
-
for (const anyT of this._anyStateTransitions) {
|
|
250
|
-
const destIndex = stateIndexMap.get(anyT.to);
|
|
251
|
-
if (destIndex === index) continue;
|
|
252
|
-
transitions.push(resolveTransition(anyT));
|
|
253
|
-
}
|
|
254
|
-
|
|
255
|
-
return {
|
|
256
|
-
name: s.name,
|
|
257
|
-
hash: index,
|
|
258
|
-
motion: {
|
|
259
|
-
name: s.options.clip.name,
|
|
260
|
-
clip: s.options.clip,
|
|
261
|
-
isLooping: s.options.loop ?? false,
|
|
262
|
-
},
|
|
263
|
-
transitions,
|
|
264
|
-
behaviours: [],
|
|
265
|
-
speed: s.options.speed,
|
|
266
|
-
speedParameter: s.options.speedParameter,
|
|
267
|
-
cycleOffset: s.options.cycleOffset,
|
|
268
|
-
cycleOffsetParameter: s.options.cycleOffsetParameter,
|
|
269
|
-
};
|
|
270
|
-
});
|
|
271
|
-
|
|
272
|
-
const model: AnimatorControllerModel = {
|
|
273
|
-
name: this._name,
|
|
274
|
-
guid: new InstantiateIdProvider(Date.now()).generateUUID(),
|
|
275
|
-
parameters: this._parameters,
|
|
276
|
-
layers: [{
|
|
277
|
-
name: "Base Layer",
|
|
278
|
-
stateMachine: {
|
|
279
|
-
defaultState: defaultStateIndex,
|
|
280
|
-
states,
|
|
281
|
-
}
|
|
282
|
-
}],
|
|
283
|
-
};
|
|
284
|
-
|
|
285
|
-
return new AnimatorController(model);
|
|
286
|
-
}
|
|
287
|
-
}
|
|
288
|
-
// #endregion
|
|
289
|
-
|
|
290
37
|
// #region AnimatorController
|
|
291
38
|
/**
|
|
292
39
|
* Controls the playback of animations using a state machine architecture.
|
|
@@ -628,6 +375,9 @@ export class AnimatorController {
|
|
|
628
375
|
/**
|
|
629
376
|
* The data model describing the animation states and transitions.
|
|
630
377
|
*/
|
|
378
|
+
// @serializable marks this for the instantiate resolve system so it traverses into the model
|
|
379
|
+
// and remaps Object3D references (e.g. motion.clips[].node) to cloned objects.
|
|
380
|
+
@serializable()
|
|
631
381
|
model: AnimatorControllerModel;
|
|
632
382
|
|
|
633
383
|
/**
|
|
@@ -647,6 +397,7 @@ export class AnimatorController {
|
|
|
647
397
|
* Stops all animations and unregisters the mixer from the animation system.
|
|
648
398
|
*/
|
|
649
399
|
dispose() {
|
|
400
|
+
if (!this._mixer) return;
|
|
650
401
|
this._mixer.stopAllAction();
|
|
651
402
|
if (this.animator) {
|
|
652
403
|
this._mixer.uncacheRoot(this.animator.gameObject);
|
|
@@ -682,38 +433,6 @@ export class AnimatorController {
|
|
|
682
433
|
}
|
|
683
434
|
}
|
|
684
435
|
|
|
685
|
-
/**
|
|
686
|
-
* Creates a deep copy of this controller.
|
|
687
|
-
* Clones the model data but does not copy runtime state.
|
|
688
|
-
*
|
|
689
|
-
* @returns A new AnimatorController instance with the same configuration
|
|
690
|
-
*/
|
|
691
|
-
clone() {
|
|
692
|
-
if (typeof this.model === "string") {
|
|
693
|
-
console.warn("AnimatorController has not been resolved, can not create model from string", this.model);
|
|
694
|
-
return null;
|
|
695
|
-
}
|
|
696
|
-
if (debug) console.warn("AnimatorController clone()", this.model);
|
|
697
|
-
// clone runtime controller but dont clone clip or action
|
|
698
|
-
const clonedModel = deepClone(this.model, (_owner, _key, _value) => {
|
|
699
|
-
if (_value === null || _value === undefined) return true;
|
|
700
|
-
// dont clone three Objects
|
|
701
|
-
if (_value.type === "Object3D" || _value.isObject3D === true) return false;
|
|
702
|
-
// dont clone AnimationAction
|
|
703
|
-
if (isAnimationAction(_value)) { //.constructor.name === "AnimationAction") {
|
|
704
|
-
// console.log(_value);
|
|
705
|
-
return false;
|
|
706
|
-
}
|
|
707
|
-
// dont clone AnimationClip
|
|
708
|
-
if (_value["tracks"] !== undefined) return false;
|
|
709
|
-
// when assigned __concreteInstance during serialization
|
|
710
|
-
if (_value instanceof AnimatorController) return false;
|
|
711
|
-
return true;
|
|
712
|
-
}) as AnimatorControllerModel;
|
|
713
|
-
console.assert(clonedModel !== this.model);
|
|
714
|
-
const controller = new AnimatorController(clonedModel);
|
|
715
|
-
return controller;
|
|
716
|
-
}
|
|
717
436
|
|
|
718
437
|
/**
|
|
719
438
|
* Updates the controller's state machine and animations.
|
|
@@ -749,8 +468,18 @@ export class AnimatorController {
|
|
|
749
468
|
get activeState(): State | undefined { return this._activeState; }
|
|
750
469
|
|
|
751
470
|
constructor(model: AnimatorControllerModel) {
|
|
752
|
-
|
|
753
|
-
|
|
471
|
+
// Deep-clone the model so each AnimatorController owns its own copy.
|
|
472
|
+
// This ensures independent parameter state and allows the instantiate
|
|
473
|
+
// resolve system to remap Object3D refs (e.g. motion.clips[].node) per instance.
|
|
474
|
+
// The predicate skips Object3D (keeps references) and AnimationClip/AnimationAction (shared resources).
|
|
475
|
+
this.model = deepClone(model, (_owner, _key, _value) => {
|
|
476
|
+
if (_value === null || _value === undefined) return true;
|
|
477
|
+
if (_value.isObject3D === true) return false;
|
|
478
|
+
if (isAnimationAction(_value)) return false;
|
|
479
|
+
if (_value["tracks"] !== undefined) return false; // AnimationClip
|
|
480
|
+
if (_value instanceof AnimatorController) return false;
|
|
481
|
+
return true;
|
|
482
|
+
}) as AnimatorControllerModel;
|
|
754
483
|
}
|
|
755
484
|
|
|
756
485
|
private _activeStates: State[] = [];
|
|
@@ -72,12 +72,14 @@ export abstract class Collider extends Behaviour implements ICollider {
|
|
|
72
72
|
* When `true` the collider will not be used for collision detection but will still trigger events.
|
|
73
73
|
* Trigger colliders can trigger events when other colliders enter their space, without creating a physical response/collision.
|
|
74
74
|
*/
|
|
75
|
+
@validate()
|
|
75
76
|
@serializable()
|
|
76
77
|
isTrigger: boolean = false;
|
|
77
78
|
|
|
78
79
|
/**
|
|
79
80
|
* The physics material that defines physical properties of the collider such as friction and bounciness.
|
|
80
81
|
*/
|
|
82
|
+
@validate()
|
|
81
83
|
@serializable()
|
|
82
84
|
sharedMaterial?: PhysicsMaterial;
|
|
83
85
|
|
|
@@ -85,15 +87,52 @@ export abstract class Collider extends Behaviour implements ICollider {
|
|
|
85
87
|
* The layers that this collider belongs to. Used for filtering collision detection.
|
|
86
88
|
* @default [0]
|
|
87
89
|
*/
|
|
90
|
+
@validate()
|
|
88
91
|
@serializable()
|
|
89
92
|
membership: number[] = [0];
|
|
90
93
|
|
|
91
94
|
/**
|
|
92
95
|
* The layers that this collider will interact with. Used for filtering collision detection.
|
|
93
96
|
*/
|
|
97
|
+
@validate()
|
|
94
98
|
@serializable()
|
|
95
99
|
filter?: number[];
|
|
96
100
|
|
|
101
|
+
/**
|
|
102
|
+
* The density of the collider, used for automatic mass calculation when the attached {@link Rigidbody} has `autoMass` enabled.
|
|
103
|
+
* Rapier computes mass from density using the real-world formula: `mass = density × volume`.
|
|
104
|
+
* The volume is derived from the collider shape (sphere, box, capsule, or convex hull).
|
|
105
|
+
*
|
|
106
|
+
* Reference values (relative to water = 1.0):
|
|
107
|
+
* - Wood: 0.5–0.9
|
|
108
|
+
* - Water: 1.0 (engine default)
|
|
109
|
+
* - Rubber: 1.2
|
|
110
|
+
* - Steel: 7.8
|
|
111
|
+
*
|
|
112
|
+
* @default undefined — uses the physics engine default of 1.0
|
|
113
|
+
*/
|
|
114
|
+
@validate()
|
|
115
|
+
@serializable()
|
|
116
|
+
density?: number;
|
|
117
|
+
|
|
118
|
+
/** @internal */
|
|
119
|
+
protected _propertiesDirty: boolean = false;
|
|
120
|
+
|
|
121
|
+
/** @internal */
|
|
122
|
+
onValidate(_property?: string) {
|
|
123
|
+
if (this.activeAndEnabled) {
|
|
124
|
+
if (_property === "sharedMaterial") {
|
|
125
|
+
this.updatePhysicsMaterial();
|
|
126
|
+
}
|
|
127
|
+
else {
|
|
128
|
+
this.updateProperties();
|
|
129
|
+
}
|
|
130
|
+
}
|
|
131
|
+
else {
|
|
132
|
+
this._propertiesDirty = true;
|
|
133
|
+
}
|
|
134
|
+
}
|
|
135
|
+
|
|
97
136
|
/** @internal */
|
|
98
137
|
awake() {
|
|
99
138
|
super.awake();
|
|
@@ -197,6 +236,11 @@ export class SphereCollider extends Collider implements ISphereCollider {
|
|
|
197
236
|
if (!this.context.physics.engine?.setColliderEnabled(this, true)) {
|
|
198
237
|
this.context.physics.engine?.addSphereCollider(this);
|
|
199
238
|
}
|
|
239
|
+
else if (this._propertiesDirty) {
|
|
240
|
+
this.updateProperties();
|
|
241
|
+
this.updatePhysicsMaterial();
|
|
242
|
+
}
|
|
243
|
+
this._propertiesDirty = false;
|
|
200
244
|
watchWrite(this.gameObject.scale, this.updateProperties);
|
|
201
245
|
}
|
|
202
246
|
|
|
@@ -208,18 +252,12 @@ export class SphereCollider extends Collider implements ISphereCollider {
|
|
|
208
252
|
unwatchWrite(this.gameObject.scale, this.updateProperties);
|
|
209
253
|
}
|
|
210
254
|
|
|
211
|
-
/**
|
|
212
|
-
* Updates collider properties when validated in the editor or inspector.
|
|
213
|
-
*/
|
|
214
|
-
onValidate(): void {
|
|
215
|
-
this.updateProperties();
|
|
216
|
-
}
|
|
217
255
|
}
|
|
218
256
|
|
|
219
257
|
/**
|
|
220
|
-
* BoxCollider represents a box-shaped (cuboid) collision volume.
|
|
221
|
-
* Most common collider type, efficient for walls, floors, crates, and rectangular objects.
|
|
222
|
-
*
|
|
258
|
+
* BoxCollider represents a box-shaped (cuboid) collision volume.
|
|
259
|
+
* Most common collider type, efficient for walls, floors, crates, and rectangular objects.
|
|
260
|
+
*
|
|
223
261
|
* 
|
|
224
262
|
*
|
|
225
263
|
* @example Create a floor collider
|
|
@@ -284,6 +322,11 @@ export class BoxCollider extends Collider implements IBoxCollider {
|
|
|
284
322
|
if (!this.context.physics.engine?.setColliderEnabled(this, true)) {
|
|
285
323
|
this.context.physics.engine?.addBoxCollider(this, this.size);
|
|
286
324
|
}
|
|
325
|
+
else if (this._propertiesDirty) {
|
|
326
|
+
this.updateProperties();
|
|
327
|
+
this.updatePhysicsMaterial();
|
|
328
|
+
}
|
|
329
|
+
this._propertiesDirty = false;
|
|
287
330
|
watchWrite(this.gameObject.scale, this.updateProperties);
|
|
288
331
|
}
|
|
289
332
|
|
|
@@ -296,14 +339,6 @@ export class BoxCollider extends Collider implements IBoxCollider {
|
|
|
296
339
|
unwatchWrite(this.gameObject.scale, this.updateProperties);
|
|
297
340
|
}
|
|
298
341
|
|
|
299
|
-
/**
|
|
300
|
-
* Updates collider properties when validated in the editor or inspector.
|
|
301
|
-
* @internal
|
|
302
|
-
*/
|
|
303
|
-
onValidate(): void {
|
|
304
|
-
this.updateProperties();
|
|
305
|
-
}
|
|
306
|
-
|
|
307
342
|
/**
|
|
308
343
|
* Automatically fits the collider to the geometry of the object.
|
|
309
344
|
* Sets the size and center based on the object's bounding box.
|
|
@@ -379,7 +414,15 @@ export class MeshCollider extends Collider {
|
|
|
379
414
|
super.onEnable();
|
|
380
415
|
if (!this.context.physics.engine) return;
|
|
381
416
|
// Re-enable existing collider instead of recreating it
|
|
382
|
-
if (this.context.physics.engine.setColliderEnabled(this, true))
|
|
417
|
+
if (this.context.physics.engine.setColliderEnabled(this, true)) {
|
|
418
|
+
if (this._propertiesDirty) {
|
|
419
|
+
this.updateProperties();
|
|
420
|
+
this.updatePhysicsMaterial();
|
|
421
|
+
}
|
|
422
|
+
this._propertiesDirty = false;
|
|
423
|
+
return;
|
|
424
|
+
}
|
|
425
|
+
this._propertiesDirty = false;
|
|
383
426
|
|
|
384
427
|
if (!this.sharedMesh?.isMesh) {
|
|
385
428
|
// HACK using the renderer mesh
|
|
@@ -475,5 +518,10 @@ export class CapsuleCollider extends Collider {
|
|
|
475
518
|
if (!this.context.physics.engine?.setColliderEnabled(this, true)) {
|
|
476
519
|
this.context.physics.engine?.addCapsuleCollider(this, this.height, this.radius);
|
|
477
520
|
}
|
|
521
|
+
else if (this._propertiesDirty) {
|
|
522
|
+
this.updateProperties();
|
|
523
|
+
this.updatePhysicsMaterial();
|
|
524
|
+
}
|
|
525
|
+
this._propertiesDirty = false;
|
|
478
526
|
}
|
|
479
527
|
}
|