@nice2dev/game-engine 1.0.2 → 1.0.4

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.
Files changed (188) hide show
  1. package/dist/cjs/ai/BehaviorTree.js +1215 -0
  2. package/dist/cjs/ai/BehaviorTree.js.map +1 -0
  3. package/dist/cjs/ai/StateMachine.js +783 -0
  4. package/dist/cjs/ai/StateMachine.js.map +1 -0
  5. package/dist/cjs/editor/ShaderGraph.js +1616 -0
  6. package/dist/cjs/editor/ShaderGraph.js.map +1 -0
  7. package/dist/cjs/editor/TimelineEditor.js +819 -0
  8. package/dist/cjs/editor/TimelineEditor.js.map +1 -0
  9. package/dist/cjs/export/GodotExporter.js +1102 -0
  10. package/dist/cjs/export/GodotExporter.js.map +1 -0
  11. package/dist/cjs/export/PlatformExporter.js +236 -0
  12. package/dist/cjs/export/PlatformExporter.js.map +1 -0
  13. package/dist/cjs/export/ThreeJSExporter.js +1116 -0
  14. package/dist/cjs/export/ThreeJSExporter.js.map +1 -0
  15. package/dist/cjs/export/UnityExporter.js +1193 -0
  16. package/dist/cjs/export/UnityExporter.js.map +1 -0
  17. package/dist/cjs/export/WebExporter.js +1036 -0
  18. package/dist/cjs/export/WebExporter.js.map +1 -0
  19. package/dist/cjs/export/index.js +58 -0
  20. package/dist/cjs/export/index.js.map +1 -0
  21. package/dist/cjs/import/AsepriteImporter.js +761 -0
  22. package/dist/cjs/import/AsepriteImporter.js.map +1 -0
  23. package/dist/cjs/import/DragonBonesImporter.js +499 -0
  24. package/dist/cjs/import/DragonBonesImporter.js.map +1 -0
  25. package/dist/cjs/import/GameMakerImporter.js +559 -0
  26. package/dist/cjs/import/GameMakerImporter.js.map +1 -0
  27. package/dist/cjs/import/GodotSceneImporter.js +824 -0
  28. package/dist/cjs/import/GodotSceneImporter.js.map +1 -0
  29. package/dist/cjs/import/LDtkImporter.js +481 -0
  30. package/dist/cjs/import/LDtkImporter.js.map +1 -0
  31. package/dist/cjs/import/Live2DImporter.js +553 -0
  32. package/dist/cjs/import/Live2DImporter.js.map +1 -0
  33. package/dist/cjs/import/NdgFormat.js +499 -0
  34. package/dist/cjs/import/NdgFormat.js.map +1 -0
  35. package/dist/cjs/import/OgmoImporter.js +529 -0
  36. package/dist/cjs/import/OgmoImporter.js.map +1 -0
  37. package/dist/cjs/import/RPGMakerImporter.js +520 -0
  38. package/dist/cjs/import/RPGMakerImporter.js.map +1 -0
  39. package/dist/cjs/import/SceneImporter.js +449 -0
  40. package/dist/cjs/import/SceneImporter.js.map +1 -0
  41. package/dist/cjs/import/SpineImporter.js +583 -0
  42. package/dist/cjs/import/SpineImporter.js.map +1 -0
  43. package/dist/cjs/import/SpriterImporter.js +652 -0
  44. package/dist/cjs/import/SpriterImporter.js.map +1 -0
  45. package/dist/cjs/import/TiledMapImporter.js +859 -0
  46. package/dist/cjs/import/TiledMapImporter.js.map +1 -0
  47. package/dist/cjs/import/UnitySceneImporter.js +732 -0
  48. package/dist/cjs/import/UnitySceneImporter.js.map +1 -0
  49. package/dist/cjs/import/index.js +305 -0
  50. package/dist/cjs/import/index.js.map +1 -0
  51. package/dist/cjs/index.js +201 -0
  52. package/dist/cjs/index.js.map +1 -1
  53. package/dist/cjs/scripting/GraphToAST.js +567 -0
  54. package/dist/cjs/scripting/GraphToAST.js.map +1 -0
  55. package/dist/cjs/scripting/LanguageExporter.js +321 -0
  56. package/dist/cjs/scripting/LanguageExporter.js.map +1 -0
  57. package/dist/cjs/scripting/ScriptAST.js +67 -0
  58. package/dist/cjs/scripting/ScriptAST.js.map +1 -0
  59. package/dist/cjs/scripting/VisualScripting2.js +1140 -0
  60. package/dist/cjs/scripting/VisualScripting2.js.map +1 -0
  61. package/dist/cjs/scripting/exporters/CSharpExporter.js +503 -0
  62. package/dist/cjs/scripting/exporters/CSharpExporter.js.map +1 -0
  63. package/dist/cjs/scripting/exporters/GDScriptExporter.js +452 -0
  64. package/dist/cjs/scripting/exporters/GDScriptExporter.js.map +1 -0
  65. package/dist/cjs/scripting/exporters/LuaExporter.js +457 -0
  66. package/dist/cjs/scripting/exporters/LuaExporter.js.map +1 -0
  67. package/dist/cjs/scripting/exporters/PythonExporter.js +565 -0
  68. package/dist/cjs/scripting/exporters/PythonExporter.js.map +1 -0
  69. package/dist/cjs/scripting/exporters/RustExporter.js +525 -0
  70. package/dist/cjs/scripting/exporters/RustExporter.js.map +1 -0
  71. package/dist/cjs/scripting/exporters/TypeScriptExporter.js +570 -0
  72. package/dist/cjs/scripting/exporters/TypeScriptExporter.js.map +1 -0
  73. package/dist/cjs/systems/ParticleSystem2.js +1478 -0
  74. package/dist/cjs/systems/ParticleSystem2.js.map +1 -0
  75. package/dist/esm/ai/BehaviorTree.js +1186 -0
  76. package/dist/esm/ai/BehaviorTree.js.map +1 -0
  77. package/dist/esm/ai/StateMachine.js +767 -0
  78. package/dist/esm/ai/StateMachine.js.map +1 -0
  79. package/dist/esm/editor/ShaderGraph.js +1606 -0
  80. package/dist/esm/editor/ShaderGraph.js.map +1 -0
  81. package/dist/esm/editor/TimelineEditor.js +800 -0
  82. package/dist/esm/editor/TimelineEditor.js.map +1 -0
  83. package/dist/esm/export/GodotExporter.js +1100 -0
  84. package/dist/esm/export/GodotExporter.js.map +1 -0
  85. package/dist/esm/export/PlatformExporter.js +230 -0
  86. package/dist/esm/export/PlatformExporter.js.map +1 -0
  87. package/dist/esm/export/ThreeJSExporter.js +1114 -0
  88. package/dist/esm/export/ThreeJSExporter.js.map +1 -0
  89. package/dist/esm/export/UnityExporter.js +1191 -0
  90. package/dist/esm/export/UnityExporter.js.map +1 -0
  91. package/dist/esm/export/WebExporter.js +1033 -0
  92. package/dist/esm/export/WebExporter.js.map +1 -0
  93. package/dist/esm/export/index.js +44 -0
  94. package/dist/esm/export/index.js.map +1 -0
  95. package/dist/esm/import/AsepriteImporter.js +759 -0
  96. package/dist/esm/import/AsepriteImporter.js.map +1 -0
  97. package/dist/esm/import/DragonBonesImporter.js +496 -0
  98. package/dist/esm/import/DragonBonesImporter.js.map +1 -0
  99. package/dist/esm/import/GameMakerImporter.js +556 -0
  100. package/dist/esm/import/GameMakerImporter.js.map +1 -0
  101. package/dist/esm/import/GodotSceneImporter.js +822 -0
  102. package/dist/esm/import/GodotSceneImporter.js.map +1 -0
  103. package/dist/esm/import/LDtkImporter.js +479 -0
  104. package/dist/esm/import/LDtkImporter.js.map +1 -0
  105. package/dist/esm/import/Live2DImporter.js +550 -0
  106. package/dist/esm/import/Live2DImporter.js.map +1 -0
  107. package/dist/esm/import/NdgFormat.js +490 -0
  108. package/dist/esm/import/NdgFormat.js.map +1 -0
  109. package/dist/esm/import/OgmoImporter.js +526 -0
  110. package/dist/esm/import/OgmoImporter.js.map +1 -0
  111. package/dist/esm/import/RPGMakerImporter.js +517 -0
  112. package/dist/esm/import/RPGMakerImporter.js.map +1 -0
  113. package/dist/esm/import/SceneImporter.js +441 -0
  114. package/dist/esm/import/SceneImporter.js.map +1 -0
  115. package/dist/esm/import/SpineImporter.js +580 -0
  116. package/dist/esm/import/SpineImporter.js.map +1 -0
  117. package/dist/esm/import/SpriterImporter.js +649 -0
  118. package/dist/esm/import/SpriterImporter.js.map +1 -0
  119. package/dist/esm/import/TiledMapImporter.js +857 -0
  120. package/dist/esm/import/TiledMapImporter.js.map +1 -0
  121. package/dist/esm/import/UnitySceneImporter.js +730 -0
  122. package/dist/esm/import/UnitySceneImporter.js.map +1 -0
  123. package/dist/esm/import/index.js +279 -0
  124. package/dist/esm/import/index.js.map +1 -0
  125. package/dist/esm/index.js +36 -0
  126. package/dist/esm/index.js.map +1 -1
  127. package/dist/esm/scripting/GraphToAST.js +564 -0
  128. package/dist/esm/scripting/GraphToAST.js.map +1 -0
  129. package/dist/esm/scripting/LanguageExporter.js +311 -0
  130. package/dist/esm/scripting/LanguageExporter.js.map +1 -0
  131. package/dist/esm/scripting/ScriptAST.js +52 -0
  132. package/dist/esm/scripting/ScriptAST.js.map +1 -0
  133. package/dist/esm/scripting/VisualScripting2.js +1130 -0
  134. package/dist/esm/scripting/VisualScripting2.js.map +1 -0
  135. package/dist/esm/scripting/exporters/CSharpExporter.js +501 -0
  136. package/dist/esm/scripting/exporters/CSharpExporter.js.map +1 -0
  137. package/dist/esm/scripting/exporters/GDScriptExporter.js +450 -0
  138. package/dist/esm/scripting/exporters/GDScriptExporter.js.map +1 -0
  139. package/dist/esm/scripting/exporters/LuaExporter.js +455 -0
  140. package/dist/esm/scripting/exporters/LuaExporter.js.map +1 -0
  141. package/dist/esm/scripting/exporters/PythonExporter.js +563 -0
  142. package/dist/esm/scripting/exporters/PythonExporter.js.map +1 -0
  143. package/dist/esm/scripting/exporters/RustExporter.js +523 -0
  144. package/dist/esm/scripting/exporters/RustExporter.js.map +1 -0
  145. package/dist/esm/scripting/exporters/TypeScriptExporter.js +568 -0
  146. package/dist/esm/scripting/exporters/TypeScriptExporter.js.map +1 -0
  147. package/dist/esm/systems/ParticleSystem2.js +1471 -0
  148. package/dist/esm/systems/ParticleSystem2.js.map +1 -0
  149. package/dist/types/ai/BehaviorTree.d.ts +375 -0
  150. package/dist/types/ai/StateMachine.d.ts +296 -0
  151. package/dist/types/editor/ShaderGraph.d.ts +207 -0
  152. package/dist/types/editor/TimelineEditor.d.ts +393 -0
  153. package/dist/types/export/GodotExporter.d.ts +56 -0
  154. package/dist/types/export/PlatformExporter.d.ts +201 -0
  155. package/dist/types/export/ThreeJSExporter.d.ts +40 -0
  156. package/dist/types/export/UnityExporter.d.ts +69 -0
  157. package/dist/types/export/WebExporter.d.ts +58 -0
  158. package/dist/types/export/index.d.ts +19 -0
  159. package/dist/types/import/AsepriteImporter.d.ts +46 -0
  160. package/dist/types/import/DragonBonesImporter.d.ts +331 -0
  161. package/dist/types/import/GameMakerImporter.d.ts +375 -0
  162. package/dist/types/import/GodotSceneImporter.d.ts +34 -0
  163. package/dist/types/import/LDtkImporter.d.ts +177 -0
  164. package/dist/types/import/Live2DImporter.d.ts +237 -0
  165. package/dist/types/import/NdgFormat.d.ts +387 -0
  166. package/dist/types/import/OgmoImporter.d.ts +237 -0
  167. package/dist/types/import/RPGMakerImporter.d.ts +186 -0
  168. package/dist/types/import/SceneImporter.d.ts +276 -0
  169. package/dist/types/import/SpineImporter.d.ts +372 -0
  170. package/dist/types/import/SpriterImporter.d.ts +230 -0
  171. package/dist/types/import/TiledMapImporter.d.ts +57 -0
  172. package/dist/types/import/UnitySceneImporter.d.ts +87 -0
  173. package/dist/types/import/index.d.ts +59 -0
  174. package/dist/types/index.d.ts +29 -17
  175. package/dist/types/scripting/GraphToAST.d.ts +55 -0
  176. package/dist/types/scripting/LanguageExporter.d.ts +136 -0
  177. package/dist/types/scripting/ScriptAST.d.ts +312 -0
  178. package/dist/types/scripting/VisualScripting2.d.ts +353 -0
  179. package/dist/types/scripting/exporters/CSharpExporter.d.ts +44 -0
  180. package/dist/types/scripting/exporters/GDScriptExporter.d.ts +46 -0
  181. package/dist/types/scripting/exporters/LuaExporter.d.ts +46 -0
  182. package/dist/types/scripting/exporters/PythonExporter.d.ts +49 -0
  183. package/dist/types/scripting/exporters/RustExporter.d.ts +46 -0
  184. package/dist/types/scripting/exporters/TypeScriptExporter.d.ts +48 -0
  185. package/dist/types/scripting/exporters/index.d.ts +8 -0
  186. package/dist/types/scripting/index.d.ts +11 -0
  187. package/dist/types/systems/ParticleSystem2.d.ts +646 -0
  188. package/package.json +3 -3
@@ -0,0 +1,783 @@
1
+ 'use strict';
2
+
3
+ /**
4
+ * @file StateMachine.ts
5
+ * @description Finite State Machine System with Graphical Editor Support
6
+ * PRO-1.4: Professional Editor Features
7
+ *
8
+ * Features:
9
+ * - Hierarchical state machines (HSM)
10
+ * - Transitions with conditions and actions
11
+ * - Entry/Exit/Update callbacks
12
+ * - Transition triggers and events
13
+ * - Visual editor integration
14
+ * - Debugging and history
15
+ * - Parallel states
16
+ * - Animation state machine support
17
+ */
18
+ // ============================================================
19
+ // State Machine Runtime
20
+ // ============================================================
21
+ class StateMachine {
22
+ constructor(definition) {
23
+ this.layerStates = new Map();
24
+ this.activeTransitions = new Map();
25
+ this.parameters = new Map();
26
+ this.triggers = new Set();
27
+ /** Callbacks */
28
+ this.onEnter = new Map();
29
+ this.onExit = new Map();
30
+ this.onUpdate = new Map();
31
+ this.onTransitionStart = [];
32
+ this.onTransitionComplete = [];
33
+ /** Event listeners */
34
+ this.eventListeners = new Map();
35
+ /** Debugging */
36
+ this.history = [];
37
+ this.historyLimit = 100;
38
+ this.debugMode = false;
39
+ this.definition = definition;
40
+ this.initializeParameters();
41
+ this.initializeLayers();
42
+ }
43
+ initializeParameters() {
44
+ for (const param of this.definition.parameters) {
45
+ this.parameters.set(param.name, param.value);
46
+ }
47
+ }
48
+ initializeLayers() {
49
+ for (const layer of this.definition.layers) {
50
+ if (!layer.active)
51
+ continue;
52
+ // Find default state or entry state
53
+ let initialState = layer.states.find((s) => s.isDefault);
54
+ if (!initialState) {
55
+ initialState = layer.states.find((s) => s.type === 'entry');
56
+ }
57
+ if (!initialState && layer.defaultState) {
58
+ initialState = layer.states.find((s) => s.id === layer.defaultState);
59
+ }
60
+ if (!initialState && layer.states.length > 0) {
61
+ initialState = layer.states[0];
62
+ }
63
+ if (initialState) {
64
+ this.layerStates.set(layer.id, {
65
+ stateId: initialState.id,
66
+ layerId: layer.id,
67
+ enterTime: 0,
68
+ elapsedTime: 0,
69
+ normalizedTime: 0,
70
+ isTransitioning: false,
71
+ });
72
+ }
73
+ }
74
+ }
75
+ // ─── Parameter Control ───────────────────────────
76
+ setParameter(name, value) {
77
+ const oldValue = this.parameters.get(name);
78
+ this.parameters.set(name, value);
79
+ if (oldValue !== value) {
80
+ this.emit('parameter-changed', { name, oldValue, newValue: value }, '');
81
+ }
82
+ }
83
+ getParameter(name) {
84
+ return this.parameters.get(name);
85
+ }
86
+ setBool(name, value) {
87
+ this.setParameter(name, value);
88
+ }
89
+ getBool(name) {
90
+ var _a;
91
+ return (_a = this.parameters.get(name)) !== null && _a !== void 0 ? _a : false;
92
+ }
93
+ setFloat(name, value) {
94
+ this.setParameter(name, value);
95
+ }
96
+ getFloat(name) {
97
+ var _a;
98
+ return (_a = this.parameters.get(name)) !== null && _a !== void 0 ? _a : 0;
99
+ }
100
+ setInteger(name, value) {
101
+ this.setParameter(name, Math.floor(value));
102
+ }
103
+ getInteger(name) {
104
+ var _a;
105
+ return Math.floor((_a = this.parameters.get(name)) !== null && _a !== void 0 ? _a : 0);
106
+ }
107
+ setTrigger(name) {
108
+ this.triggers.add(name);
109
+ this.setParameter(name, true);
110
+ }
111
+ resetTrigger(name) {
112
+ this.triggers.delete(name);
113
+ this.setParameter(name, false);
114
+ }
115
+ // ─── Update ──────────────────────────────────────
116
+ update(context) {
117
+ for (const layer of this.definition.layers) {
118
+ if (!layer.active)
119
+ continue;
120
+ this.updateLayer(layer, context);
121
+ }
122
+ // Clear triggers after processing
123
+ this.triggers.clear();
124
+ for (const param of this.definition.parameters) {
125
+ if (param.type === 'trigger') {
126
+ this.parameters.set(param.name, false);
127
+ }
128
+ }
129
+ }
130
+ updateLayer(layer, context) {
131
+ const stateInstance = this.layerStates.get(layer.id);
132
+ if (!stateInstance)
133
+ return;
134
+ const currentState = layer.states.find((s) => s.id === stateInstance.stateId);
135
+ if (!currentState)
136
+ return;
137
+ // Update elapsed time
138
+ stateInstance.elapsedTime += context.dt;
139
+ // Check for transitions
140
+ const activeTransition = this.activeTransitions.get(layer.id);
141
+ if (activeTransition) {
142
+ // Update transition progress
143
+ activeTransition.progress += context.dt / activeTransition.duration;
144
+ if (activeTransition.progress >= 1) {
145
+ // Complete transition
146
+ this.completeTransition(layer, activeTransition, context);
147
+ }
148
+ }
149
+ else {
150
+ // Check for new transitions
151
+ const transition = this.findValidTransition(layer, currentState);
152
+ if (transition) {
153
+ this.startTransition(layer, transition, context);
154
+ }
155
+ else {
156
+ // Update current state
157
+ stateInstance.isTransitioning = false;
158
+ this.callOnUpdate(currentState, context);
159
+ }
160
+ }
161
+ }
162
+ findValidTransition(layer, currentState) {
163
+ // Sort by priority (lower = higher priority)
164
+ const allTransitions = [
165
+ ...layer.anyStateTransitions,
166
+ ...layer.transitions.filter((t) => t.from === currentState.id),
167
+ ].sort((a, b) => a.priority - b.priority);
168
+ for (const transition of allTransitions) {
169
+ if (transition.muted)
170
+ continue;
171
+ // Check if can interrupt
172
+ const activeTransition = this.activeTransitions.get(layer.id);
173
+ if (activeTransition && !transition.canInterrupt)
174
+ continue;
175
+ // Check trigger
176
+ if (transition.trigger && !this.triggers.has(transition.trigger)) {
177
+ continue;
178
+ }
179
+ // Check conditions
180
+ if (this.evaluateConditions(transition.conditions)) {
181
+ return transition;
182
+ }
183
+ }
184
+ return null;
185
+ }
186
+ evaluateConditions(groups) {
187
+ if (groups.length === 0)
188
+ return true;
189
+ for (const group of groups) {
190
+ const groupResult = this.evaluateConditionGroup(group);
191
+ if (!groupResult)
192
+ return false;
193
+ }
194
+ return true;
195
+ }
196
+ evaluateConditionGroup(group) {
197
+ if (group.conditions.length === 0)
198
+ return true;
199
+ const results = group.conditions.map((c) => this.evaluateCondition(c));
200
+ if (group.mode === 'and') {
201
+ return results.every((r) => r);
202
+ }
203
+ else {
204
+ return results.some((r) => r);
205
+ }
206
+ }
207
+ evaluateCondition(condition) {
208
+ const paramValue = this.parameters.get(condition.parameter);
209
+ if (paramValue === undefined)
210
+ return false;
211
+ switch (condition.operator) {
212
+ case 'equals':
213
+ return paramValue === condition.value;
214
+ case 'notEquals':
215
+ return paramValue !== condition.value;
216
+ case 'greater':
217
+ return paramValue > condition.value;
218
+ case 'less':
219
+ return paramValue < condition.value;
220
+ case 'greaterEqual':
221
+ return paramValue >= condition.value;
222
+ case 'lessEqual':
223
+ return paramValue <= condition.value;
224
+ default:
225
+ return false;
226
+ }
227
+ }
228
+ startTransition(layer, transition, context) {
229
+ const stateInstance = this.layerStates.get(layer.id);
230
+ if (!stateInstance)
231
+ return;
232
+ const fromState = layer.states.find((s) => s.id === stateInstance.stateId);
233
+ const toState = layer.states.find((s) => s.id === transition.to);
234
+ if (!toState)
235
+ return;
236
+ // Call exit on current state
237
+ if (fromState) {
238
+ this.callOnExit(fromState, context);
239
+ }
240
+ // Create transition instance
241
+ const transitionInstance = {
242
+ transitionId: transition.id,
243
+ fromState: stateInstance.stateId,
244
+ toState: transition.to,
245
+ startTime: context.time,
246
+ duration: transition.duration,
247
+ progress: 0,
248
+ };
249
+ this.activeTransitions.set(layer.id, transitionInstance);
250
+ stateInstance.isTransitioning = true;
251
+ // Call transition callbacks
252
+ for (const cb of this.onTransitionStart) {
253
+ cb(context, transition);
254
+ }
255
+ this.emit('transition-start', { transition, from: fromState, to: toState }, layer.id);
256
+ // If instant transition, complete immediately
257
+ if (transition.duration === 0) {
258
+ this.completeTransition(layer, transitionInstance, context);
259
+ }
260
+ }
261
+ completeTransition(layer, transitionInstance, context) {
262
+ const stateInstance = this.layerStates.get(layer.id);
263
+ if (!stateInstance)
264
+ return;
265
+ const toState = layer.states.find((s) => s.id === transitionInstance.toState);
266
+ const transition = layer.transitions.find((t) => t.id === transitionInstance.transitionId) ||
267
+ layer.anyStateTransitions.find((t) => t.id === transitionInstance.transitionId);
268
+ if (!toState)
269
+ return;
270
+ // Update state
271
+ stateInstance.stateId = transitionInstance.toState;
272
+ stateInstance.enterTime = context.time;
273
+ stateInstance.elapsedTime = 0;
274
+ stateInstance.normalizedTime = (transition === null || transition === void 0 ? void 0 : transition.targetOffset) || 0;
275
+ stateInstance.isTransitioning = false;
276
+ // Remove active transition
277
+ this.activeTransitions.delete(layer.id);
278
+ // Call enter on new state
279
+ this.callOnEnter(toState, context);
280
+ // Call transition complete callbacks
281
+ if (transition) {
282
+ for (const cb of this.onTransitionComplete) {
283
+ cb(context, transition);
284
+ }
285
+ }
286
+ this.emit('transition-complete', { transition, state: toState }, layer.id);
287
+ }
288
+ // ─── Callbacks ───────────────────────────────────
289
+ callOnEnter(state, context) {
290
+ const callbacks = this.onEnter.get(state.id);
291
+ if (callbacks) {
292
+ for (const cb of callbacks) {
293
+ cb(context, state);
294
+ }
295
+ }
296
+ this.emit('state-enter', { state }, state.id);
297
+ }
298
+ callOnExit(state, context) {
299
+ const callbacks = this.onExit.get(state.id);
300
+ if (callbacks) {
301
+ for (const cb of callbacks) {
302
+ cb(context, state);
303
+ }
304
+ }
305
+ this.emit('state-exit', { state }, state.id);
306
+ }
307
+ callOnUpdate(state, context) {
308
+ const callbacks = this.onUpdate.get(state.id);
309
+ if (callbacks) {
310
+ for (const cb of callbacks) {
311
+ cb(context, state);
312
+ }
313
+ }
314
+ this.emit('state-update', { state }, state.id);
315
+ }
316
+ // ─── Registration ────────────────────────────────
317
+ registerOnEnter(stateId, callback) {
318
+ let callbacks = this.onEnter.get(stateId);
319
+ if (!callbacks) {
320
+ callbacks = [];
321
+ this.onEnter.set(stateId, callbacks);
322
+ }
323
+ callbacks.push(callback);
324
+ }
325
+ registerOnExit(stateId, callback) {
326
+ let callbacks = this.onExit.get(stateId);
327
+ if (!callbacks) {
328
+ callbacks = [];
329
+ this.onExit.set(stateId, callbacks);
330
+ }
331
+ callbacks.push(callback);
332
+ }
333
+ registerOnUpdate(stateId, callback) {
334
+ let callbacks = this.onUpdate.get(stateId);
335
+ if (!callbacks) {
336
+ callbacks = [];
337
+ this.onUpdate.set(stateId, callbacks);
338
+ }
339
+ callbacks.push(callback);
340
+ }
341
+ registerOnTransitionStart(callback) {
342
+ this.onTransitionStart.push(callback);
343
+ }
344
+ registerOnTransitionComplete(callback) {
345
+ this.onTransitionComplete.push(callback);
346
+ }
347
+ // ─── Events ──────────────────────────────────────
348
+ on(event, listener) {
349
+ let listeners = this.eventListeners.get(event);
350
+ if (!listeners) {
351
+ listeners = [];
352
+ this.eventListeners.set(event, listeners);
353
+ }
354
+ listeners.push(listener);
355
+ }
356
+ off(event, listener) {
357
+ const listeners = this.eventListeners.get(event);
358
+ if (listeners) {
359
+ const idx = listeners.indexOf(listener);
360
+ if (idx >= 0) {
361
+ listeners.splice(idx, 1);
362
+ }
363
+ }
364
+ }
365
+ emit(type, data, layerId) {
366
+ const event = {
367
+ type,
368
+ timestamp: Date.now(),
369
+ layerId,
370
+ data,
371
+ };
372
+ // Record history
373
+ if (this.debugMode) {
374
+ this.history.push(event);
375
+ if (this.history.length > this.historyLimit) {
376
+ this.history.shift();
377
+ }
378
+ }
379
+ // Notify listeners
380
+ const listeners = this.eventListeners.get(type);
381
+ if (listeners) {
382
+ for (const listener of listeners) {
383
+ listener(event);
384
+ }
385
+ }
386
+ }
387
+ // ─── State Queries ───────────────────────────────
388
+ getCurrentState(layerId) {
389
+ var _a;
390
+ const targetLayerId = layerId || ((_a = this.definition.layers[0]) === null || _a === void 0 ? void 0 : _a.id);
391
+ if (!targetLayerId)
392
+ return null;
393
+ const stateInstance = this.layerStates.get(targetLayerId);
394
+ if (!stateInstance)
395
+ return null;
396
+ const layer = this.definition.layers.find((l) => l.id === targetLayerId);
397
+ if (!layer)
398
+ return null;
399
+ return layer.states.find((s) => s.id === stateInstance.stateId) || null;
400
+ }
401
+ getCurrentStateId(layerId) {
402
+ const state = this.getCurrentState(layerId);
403
+ return (state === null || state === void 0 ? void 0 : state.id) || null;
404
+ }
405
+ isInState(stateId, layerId) {
406
+ const currentId = this.getCurrentStateId(layerId);
407
+ return currentId === stateId;
408
+ }
409
+ isTransitioning(layerId) {
410
+ var _a;
411
+ const targetLayerId = layerId || ((_a = this.definition.layers[0]) === null || _a === void 0 ? void 0 : _a.id);
412
+ if (!targetLayerId)
413
+ return false;
414
+ return this.activeTransitions.has(targetLayerId);
415
+ }
416
+ getTransitionProgress(layerId) {
417
+ var _a;
418
+ const targetLayerId = layerId || ((_a = this.definition.layers[0]) === null || _a === void 0 ? void 0 : _a.id);
419
+ if (!targetLayerId)
420
+ return 0;
421
+ const transition = this.activeTransitions.get(targetLayerId);
422
+ return (transition === null || transition === void 0 ? void 0 : transition.progress) || 0;
423
+ }
424
+ getStateTime(layerId) {
425
+ var _a;
426
+ const targetLayerId = layerId || ((_a = this.definition.layers[0]) === null || _a === void 0 ? void 0 : _a.id);
427
+ if (!targetLayerId)
428
+ return 0;
429
+ const stateInstance = this.layerStates.get(targetLayerId);
430
+ return (stateInstance === null || stateInstance === void 0 ? void 0 : stateInstance.elapsedTime) || 0;
431
+ }
432
+ // ─── Manual Control ──────────────────────────────
433
+ forceState(stateId, layerId) {
434
+ var _a;
435
+ const targetLayerId = layerId || ((_a = this.definition.layers[0]) === null || _a === void 0 ? void 0 : _a.id);
436
+ if (!targetLayerId)
437
+ return;
438
+ const layer = this.definition.layers.find((l) => l.id === targetLayerId);
439
+ if (!layer)
440
+ return;
441
+ const state = layer.states.find((s) => s.id === stateId);
442
+ if (!state)
443
+ return;
444
+ // Clear any active transition
445
+ this.activeTransitions.delete(targetLayerId);
446
+ // Set state directly
447
+ this.layerStates.set(targetLayerId, {
448
+ stateId,
449
+ layerId: targetLayerId,
450
+ enterTime: 0,
451
+ elapsedTime: 0,
452
+ normalizedTime: 0,
453
+ isTransitioning: false,
454
+ });
455
+ }
456
+ reset() {
457
+ this.layerStates.clear();
458
+ this.activeTransitions.clear();
459
+ this.triggers.clear();
460
+ this.initializeParameters();
461
+ this.initializeLayers();
462
+ this.history = [];
463
+ }
464
+ // ─── Debugging ───────────────────────────────────
465
+ getHistory() {
466
+ return [...this.history];
467
+ }
468
+ clearHistory() {
469
+ this.history = [];
470
+ }
471
+ getDebugInfo() {
472
+ const layers = this.definition.layers.map((layer) => {
473
+ const stateInstance = this.layerStates.get(layer.id);
474
+ const transition = this.activeTransitions.get(layer.id);
475
+ return {
476
+ id: layer.id,
477
+ name: layer.name,
478
+ currentState: (stateInstance === null || stateInstance === void 0 ? void 0 : stateInstance.stateId) || null,
479
+ isTransitioning: !!transition,
480
+ transitionProgress: (transition === null || transition === void 0 ? void 0 : transition.progress) || 0,
481
+ };
482
+ });
483
+ const parameters = {};
484
+ for (const [name, value] of this.parameters) {
485
+ parameters[name] = value;
486
+ }
487
+ return { layers, parameters };
488
+ }
489
+ // ─── Serialization ───────────────────────────────
490
+ getDefinition() {
491
+ return this.definition;
492
+ }
493
+ clone() {
494
+ return new StateMachine(JSON.parse(JSON.stringify(this.definition)));
495
+ }
496
+ }
497
+ // ============================================================
498
+ // Animation State Machine
499
+ // ============================================================
500
+ /** Extended state machine for animation control */
501
+ class AnimatorController extends StateMachine {
502
+ constructor(definition) {
503
+ super(definition);
504
+ this.motionValues = new Map();
505
+ this.blendTrees = new Map();
506
+ }
507
+ /** Get blended motion value for animation sampling */
508
+ getMotionValue(layerId) {
509
+ return this.motionValues.get(layerId) || 0;
510
+ }
511
+ /** Get current motion/clip name */
512
+ getMotionClip(layerId) {
513
+ const state = this.getCurrentState(layerId);
514
+ return (state === null || state === void 0 ? void 0 : state.motion) || null;
515
+ }
516
+ /** Register a blend tree for a state */
517
+ registerBlendTree(stateId, blendTree) {
518
+ this.blendTrees.set(stateId, blendTree);
519
+ }
520
+ /** Sample blend tree for current parameters */
521
+ sampleBlendTree(stateId) {
522
+ const blendTree = this.blendTrees.get(stateId);
523
+ if (!blendTree)
524
+ return null;
525
+ const params = {};
526
+ for (const [name, value] of this.getParameterMap()) {
527
+ if (typeof value === 'number') {
528
+ params[name] = value;
529
+ }
530
+ }
531
+ return blendTree.sample(params);
532
+ }
533
+ getParameterMap() {
534
+ const map = new Map();
535
+ const definition = this.getDefinition();
536
+ for (const param of definition.parameters) {
537
+ const value = this.getParameter(param.name);
538
+ if (value !== undefined) {
539
+ map.set(param.name, value);
540
+ }
541
+ }
542
+ return map;
543
+ }
544
+ }
545
+ class BlendTree {
546
+ constructor(type, parameterX, parameterY) {
547
+ this.motions = [];
548
+ this.type = type;
549
+ this.parameterX = parameterX;
550
+ this.parameterY = parameterY;
551
+ }
552
+ addMotion(motion) {
553
+ this.motions.push(motion);
554
+ }
555
+ sample(parameters) {
556
+ const paramX = parameters[this.parameterX] || 0;
557
+ const paramY = this.parameterY ? parameters[this.parameterY] || 0 : 0;
558
+ switch (this.type) {
559
+ case '1d':
560
+ return this.sample1D(paramX);
561
+ case '2d-simple':
562
+ case '2d-freeform':
563
+ return this.sample2D(paramX, paramY);
564
+ case 'direct':
565
+ return this.sampleDirect(parameters);
566
+ default:
567
+ return { clips: [] };
568
+ }
569
+ }
570
+ sample1D(value) {
571
+ if (this.motions.length === 0)
572
+ return { clips: [] };
573
+ // Sort by threshold/position
574
+ const sorted = [...this.motions].sort((a, b) => a.position - b.position);
575
+ // Find two motions to blend between
576
+ let lower = sorted[0];
577
+ let upper = sorted[sorted.length - 1];
578
+ for (let i = 0; i < sorted.length - 1; i++) {
579
+ const posLower = sorted[i].position;
580
+ const posUpper = sorted[i + 1].position;
581
+ if (value >= posLower && value <= posUpper) {
582
+ lower = sorted[i];
583
+ upper = sorted[i + 1];
584
+ break;
585
+ }
586
+ }
587
+ const posLower = lower.position;
588
+ const posUpper = upper.position;
589
+ // Calculate blend weight
590
+ let t = 0;
591
+ if (posUpper !== posLower) {
592
+ t = (value - posLower) / (posUpper - posLower);
593
+ }
594
+ t = Math.max(0, Math.min(1, t));
595
+ const clips = [];
596
+ if (t < 1) {
597
+ clips.push({
598
+ clip: lower.clip,
599
+ weight: 1 - t,
600
+ speed: lower.speed || 1,
601
+ mirror: lower.mirror || false,
602
+ });
603
+ }
604
+ if (t > 0 && upper !== lower) {
605
+ clips.push({
606
+ clip: upper.clip,
607
+ weight: t,
608
+ speed: upper.speed || 1,
609
+ mirror: upper.mirror || false,
610
+ });
611
+ }
612
+ return { clips };
613
+ }
614
+ sample2D(x, y) {
615
+ if (this.motions.length === 0)
616
+ return { clips: [] };
617
+ // Calculate weights using inverse distance weighting
618
+ const clips = [];
619
+ const weights = [];
620
+ let totalWeight = 0;
621
+ for (const motion of this.motions) {
622
+ const pos = motion.position;
623
+ const dx = x - pos.x;
624
+ const dy = y - pos.y;
625
+ const dist = Math.sqrt(dx * dx + dy * dy);
626
+ // Inverse distance (with small epsilon to avoid division by zero)
627
+ const weight = 1 / (dist + 0.001);
628
+ weights.push(weight);
629
+ totalWeight += weight;
630
+ }
631
+ // Normalize weights and create result
632
+ for (let i = 0; i < this.motions.length; i++) {
633
+ const motion = this.motions[i];
634
+ const normalizedWeight = weights[i] / totalWeight;
635
+ if (normalizedWeight > 0.001) {
636
+ clips.push({
637
+ clip: motion.clip,
638
+ weight: normalizedWeight,
639
+ speed: motion.speed || 1,
640
+ mirror: motion.mirror || false,
641
+ });
642
+ }
643
+ }
644
+ return { clips };
645
+ }
646
+ sampleDirect(parameters) {
647
+ const clips = [];
648
+ let totalWeight = 0;
649
+ for (const motion of this.motions) {
650
+ const weight = parameters[motion.clip] || 0;
651
+ if (weight > 0) {
652
+ totalWeight += weight;
653
+ clips.push({
654
+ clip: motion.clip,
655
+ weight,
656
+ speed: motion.speed || 1,
657
+ mirror: motion.mirror || false,
658
+ });
659
+ }
660
+ }
661
+ // Normalize
662
+ if (totalWeight > 0) {
663
+ for (const clip of clips) {
664
+ clip.weight /= totalWeight;
665
+ }
666
+ }
667
+ return { clips };
668
+ }
669
+ }
670
+ // ============================================================
671
+ // Factory Functions
672
+ // ============================================================
673
+ function createStateMachine(definition) {
674
+ return new StateMachine(definition);
675
+ }
676
+ function createAnimatorController(definition) {
677
+ return new AnimatorController(definition);
678
+ }
679
+ function createBlendTree1D(parameter) {
680
+ return new BlendTree('1d', parameter);
681
+ }
682
+ function createBlendTree2D(parameterX, parameterY, type = '2d-simple') {
683
+ return new BlendTree(type, parameterX, parameterY);
684
+ }
685
+ function createSMDefinition(name) {
686
+ return {
687
+ id: `sm_${Date.now()}_${Math.random().toString(36).substr(2, 9)}`,
688
+ name,
689
+ description: '',
690
+ parameters: [],
691
+ layers: [],
692
+ };
693
+ }
694
+ function createSMLayer(name) {
695
+ return {
696
+ id: `layer_${Date.now()}_${Math.random().toString(36).substr(2, 9)}`,
697
+ name,
698
+ weight: 1,
699
+ blendMode: 'override',
700
+ active: true,
701
+ states: [],
702
+ transitions: [],
703
+ anyStateTransitions: [],
704
+ };
705
+ }
706
+ function createSMState(name, type = 'normal') {
707
+ return {
708
+ id: `state_${Date.now()}_${Math.random().toString(36).substr(2, 9)}`,
709
+ name,
710
+ type,
711
+ position: { x: 0, y: 0 },
712
+ speed: 1,
713
+ };
714
+ }
715
+ function createSMTransition(from, to) {
716
+ return {
717
+ id: `trans_${Date.now()}_${Math.random().toString(36).substr(2, 9)}`,
718
+ from,
719
+ to,
720
+ conditions: [],
721
+ duration: 0.1,
722
+ priority: 0,
723
+ canInterrupt: false,
724
+ };
725
+ }
726
+ function createSMParameter(name, type, value) {
727
+ let defaultValue;
728
+ switch (type) {
729
+ case 'bool':
730
+ case 'trigger':
731
+ defaultValue = value !== undefined ? value : false;
732
+ break;
733
+ case 'int':
734
+ defaultValue = value !== undefined ? Math.floor(value) : 0;
735
+ break;
736
+ case 'float':
737
+ defaultValue = value !== undefined ? value : 0;
738
+ break;
739
+ }
740
+ return {
741
+ name,
742
+ type,
743
+ value: defaultValue,
744
+ };
745
+ }
746
+ function createSMCondition(parameter, operator, value) {
747
+ return {
748
+ id: `cond_${Date.now()}_${Math.random().toString(36).substr(2, 9)}`,
749
+ parameter,
750
+ operator,
751
+ value,
752
+ };
753
+ }
754
+ function createSMConditionGroup(mode = 'and') {
755
+ return {
756
+ id: `group_${Date.now()}_${Math.random().toString(36).substr(2, 9)}`,
757
+ mode,
758
+ conditions: [],
759
+ };
760
+ }
761
+ function createSMContext(params) {
762
+ return {
763
+ ...params,
764
+ services: new Map(),
765
+ };
766
+ }
767
+
768
+ exports.AnimatorController = AnimatorController;
769
+ exports.BlendTree = BlendTree;
770
+ exports.StateMachine = StateMachine;
771
+ exports.createAnimatorController = createAnimatorController;
772
+ exports.createBlendTree1D = createBlendTree1D;
773
+ exports.createBlendTree2D = createBlendTree2D;
774
+ exports.createSMCondition = createSMCondition;
775
+ exports.createSMConditionGroup = createSMConditionGroup;
776
+ exports.createSMContext = createSMContext;
777
+ exports.createSMDefinition = createSMDefinition;
778
+ exports.createSMLayer = createSMLayer;
779
+ exports.createSMParameter = createSMParameter;
780
+ exports.createSMState = createSMState;
781
+ exports.createSMTransition = createSMTransition;
782
+ exports.createStateMachine = createStateMachine;
783
+ //# sourceMappingURL=StateMachine.js.map