@nice2dev/game-engine 1.3.14 → 1.3.16

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 (434) hide show
  1. package/CHANGELOG.md +13 -0
  2. package/dist/cjs/accessibility/Accessibility.js +152 -165
  3. package/dist/cjs/ai/AI.js +292 -294
  4. package/dist/cjs/ai/BehaviorTree.js +1029 -1113
  5. package/dist/cjs/ai/StateMachine.js +694 -756
  6. package/dist/cjs/animation/Animation.js +232 -241
  7. package/dist/cjs/audio/AudioAdvanced.js +221 -236
  8. package/dist/cjs/audio/AudioBridge.js +441 -435
  9. package/dist/cjs/audio/AudioManager.js +242 -259
  10. package/dist/cjs/build-cloud/BuildOrchestration.js +1059 -1098
  11. package/dist/cjs/build-cloud/GodotBuildCloud.js +641 -670
  12. package/dist/cjs/build-cloud/UnityBuildCloud.js +563 -610
  13. package/dist/cjs/build-cloud/UnrealBuildCloud.js +610 -635
  14. package/dist/cjs/core/EventBus.js +51 -56
  15. package/dist/cjs/core/GameClock.js +62 -66
  16. package/dist/cjs/core/GameConfig.js +72 -79
  17. package/dist/cjs/core/GameLoop.js +80 -89
  18. package/dist/cjs/core/ServiceLocator.js +61 -65
  19. package/dist/cjs/core/Validation.js +72 -82
  20. package/dist/cjs/core/math.js +108 -112
  21. package/dist/cjs/devtools/DevTools.js +542 -563
  22. package/dist/cjs/devtools/DeveloperExperience.js +521 -559
  23. package/dist/cjs/devtools/GameplayAnalytics.js +636 -646
  24. package/dist/cjs/dialogue/DialogueSystem.js +984 -986
  25. package/dist/cjs/docs/DocGenerator.js +339 -364
  26. package/dist/cjs/ecs/World.js +355 -371
  27. package/dist/cjs/editor/AchievementEditor.js +580 -636
  28. package/dist/cjs/editor/AdvancedEditor.js +184 -191
  29. package/dist/cjs/editor/AnimationRetargeting.js +696 -741
  30. package/dist/cjs/editor/AssetBrowser.js +1072 -1160
  31. package/dist/cjs/editor/AssetManager.js +187 -192
  32. package/dist/cjs/editor/ConsolePro.js +971 -1061
  33. package/dist/cjs/editor/CraftingEditor.js +680 -730
  34. package/dist/cjs/editor/DebugTools.js +187 -185
  35. package/dist/cjs/editor/DialogueSystem.js +844 -901
  36. package/dist/cjs/editor/LeaderboardSystem.js +429 -483
  37. package/dist/cjs/editor/NiceGameEditor.js +1903 -1201
  38. package/dist/cjs/editor/PrefabSystem.js +772 -838
  39. package/dist/cjs/editor/ProfilerPanel.js +649 -700
  40. package/dist/cjs/editor/QuestEditor.js +792 -839
  41. package/dist/cjs/editor/ReplaySystem.js +585 -634
  42. package/dist/cjs/editor/SceneEditor.js +176 -200
  43. package/dist/cjs/editor/ScreenshotMode.js +621 -688
  44. package/dist/cjs/editor/ShaderGraph.js +1556 -1582
  45. package/dist/cjs/editor/TimelineEditor.js +715 -778
  46. package/dist/cjs/editor/UndoRedoPro.js +830 -904
  47. package/dist/cjs/editor/VRARMode.js +582 -645
  48. package/dist/cjs/engine/NiceGameEngine.js +141 -164
  49. package/dist/cjs/engine/SaveSystem.js +441 -495
  50. package/dist/cjs/enterprise/Enterprise.js +254 -261
  51. package/dist/cjs/export/BevyExporter.js +927 -967
  52. package/dist/cjs/export/CocosExporter.js +644 -673
  53. package/dist/cjs/export/Construct3Exporter.js +783 -794
  54. package/dist/cjs/export/DefoldExporter.js +1028 -1069
  55. package/dist/cjs/export/GDevelopExporter.js +674 -708
  56. package/dist/cjs/export/GameMakerExporter.js +791 -805
  57. package/dist/cjs/export/GodotExporter.js +1003 -1045
  58. package/dist/cjs/export/MinecraftBedrockExporter.js +573 -578
  59. package/dist/cjs/export/MonoGameExporter.js +1265 -1293
  60. package/dist/cjs/export/Pico8Exporter.js +766 -812
  61. package/dist/cjs/export/PlatformExporter.js +188 -206
  62. package/dist/cjs/export/RPGMakerExporter.js +860 -879
  63. package/dist/cjs/export/RobloxExporter.js +883 -919
  64. package/dist/cjs/export/Solar2DExporter.js +1218 -1256
  65. package/dist/cjs/export/ThreeJSExporter.js +1006 -1073
  66. package/dist/cjs/export/Tic80Exporter.js +1210 -1267
  67. package/dist/cjs/export/UnityExporter.js +1116 -1131
  68. package/dist/cjs/export/UnrealExporter.js +889 -919
  69. package/dist/cjs/export/WebExporter.js +931 -970
  70. package/dist/cjs/export/index.js +42 -65
  71. package/dist/cjs/godot-integration/GodotAssetLibrary.js +659 -692
  72. package/dist/cjs/godot-integration/GodotImport.js +929 -1027
  73. package/dist/cjs/godot-integration/GodotLiveLink.js +915 -945
  74. package/dist/cjs/godot-integration/components/GodotProjectBrowser.js +911 -611
  75. package/dist/cjs/i18n/I18n.js +860 -900
  76. package/dist/cjs/i18n/useTranslation.js +84 -89
  77. package/dist/cjs/import/AsepriteImporter.js +658 -716
  78. package/dist/cjs/import/DragonBonesImporter.js +437 -461
  79. package/dist/cjs/import/GameMakerImporter.js +511 -521
  80. package/dist/cjs/import/GodotSceneImporter.js +788 -822
  81. package/dist/cjs/import/LDtkImporter.js +436 -454
  82. package/dist/cjs/import/Live2DImporter.js +497 -518
  83. package/dist/cjs/import/NdgFormat.js +424 -457
  84. package/dist/cjs/import/OgmoImporter.js +466 -493
  85. package/dist/cjs/import/RPGMakerImporter.js +451 -477
  86. package/dist/cjs/import/SceneImporter.js +378 -423
  87. package/dist/cjs/import/SpineImporter.js +511 -546
  88. package/dist/cjs/import/SpriterImporter.js +590 -613
  89. package/dist/cjs/import/TiledMapImporter.js +811 -846
  90. package/dist/cjs/import/UnitySceneImporter.js +687 -703
  91. package/dist/cjs/import/index.js +206 -251
  92. package/dist/cjs/index.js +275 -278
  93. package/dist/cjs/input/GamepadNavigation.js +185 -205
  94. package/dist/cjs/input/InputManager.js +397 -421
  95. package/dist/cjs/input/useGamepads.js +70 -81
  96. package/dist/cjs/integration/IconSprite.js +129 -256
  97. package/dist/cjs/inventory/InventorySystem.js +920 -995
  98. package/dist/cjs/kids/KidMode.js +997 -1022
  99. package/dist/cjs/kids/KidTools.js +570 -594
  100. package/dist/cjs/monetization/Monetization.js +170 -177
  101. package/dist/cjs/multiplayer/LocalMultiplayer.js +287 -287
  102. package/dist/cjs/multiplayer/MiniGameTypes.js +49 -59
  103. package/dist/cjs/native-engine/AnimationSystem.js +731 -806
  104. package/dist/cjs/native-engine/AssetPipeline.js +454 -515
  105. package/dist/cjs/native-engine/AudioEngine.js +763 -804
  106. package/dist/cjs/native-engine/InputSystem.js +1075 -1145
  107. package/dist/cjs/native-engine/NetworkingSystem.js +733 -793
  108. package/dist/cjs/native-engine/PhysicsEngine.js +583 -607
  109. package/dist/cjs/native-engine/RenderingEngine.js +302 -350
  110. package/dist/cjs/native-engine/SceneGraph.js +769 -808
  111. package/dist/cjs/network/MultiplayerTransport.js +97 -132
  112. package/dist/cjs/network/Networking.js +549 -564
  113. package/dist/cjs/node_modules/@microsoft/signalr/dist/esm/AbortController.js +21 -29
  114. package/dist/cjs/node_modules/@microsoft/signalr/dist/esm/AccessTokenHttpClient.js +40 -48
  115. package/dist/cjs/node_modules/@microsoft/signalr/dist/esm/DefaultHttpClient.js +35 -43
  116. package/dist/cjs/node_modules/@microsoft/signalr/dist/esm/DefaultReconnectPolicy.js +10 -15
  117. package/dist/cjs/node_modules/@microsoft/signalr/dist/esm/Errors.js +103 -135
  118. package/dist/cjs/node_modules/@microsoft/signalr/dist/esm/FetchHttpClient.js +131 -158
  119. package/dist/cjs/node_modules/@microsoft/signalr/dist/esm/HandshakeProtocol.js +39 -53
  120. package/dist/cjs/node_modules/@microsoft/signalr/dist/esm/HeaderNames.js +5 -8
  121. package/dist/cjs/node_modules/@microsoft/signalr/dist/esm/HttpClient.js +40 -48
  122. package/dist/cjs/node_modules/@microsoft/signalr/dist/esm/HttpConnection.js +494 -572
  123. package/dist/cjs/node_modules/@microsoft/signalr/dist/esm/HubConnection.js +826 -953
  124. package/dist/cjs/node_modules/@microsoft/signalr/dist/esm/HubConnectionBuilder.js +125 -146
  125. package/dist/cjs/node_modules/@microsoft/signalr/dist/esm/IHubProtocol.js +13 -23
  126. package/dist/cjs/node_modules/@microsoft/signalr/dist/esm/ILogger.js +11 -25
  127. package/dist/cjs/node_modules/@microsoft/signalr/dist/esm/ITransport.js +13 -24
  128. package/dist/cjs/node_modules/@microsoft/signalr/dist/esm/JsonHubProtocol.js +108 -121
  129. package/dist/cjs/node_modules/@microsoft/signalr/dist/esm/Loggers.js +10 -14
  130. package/dist/cjs/node_modules/@microsoft/signalr/dist/esm/LongPollingTransport.js +150 -185
  131. package/dist/cjs/node_modules/@microsoft/signalr/dist/esm/MessageBuffer.js +158 -196
  132. package/dist/cjs/node_modules/@microsoft/signalr/dist/esm/ServerSentEventsTransport.js +90 -105
  133. package/dist/cjs/node_modules/@microsoft/signalr/dist/esm/Subject.js +30 -35
  134. package/dist/cjs/node_modules/@microsoft/signalr/dist/esm/TextMessageFormat.js +16 -21
  135. package/dist/cjs/node_modules/@microsoft/signalr/dist/esm/Utils.js +215 -248
  136. package/dist/cjs/node_modules/@microsoft/signalr/dist/esm/WebSocketTransport.js +135 -157
  137. package/dist/cjs/node_modules/@microsoft/signalr/dist/esm/XhrHttpClient.js +76 -85
  138. package/dist/cjs/node_modules/@microsoft/signalr/dist/esm/index.js +24 -27
  139. package/dist/cjs/node_modules/@microsoft/signalr/dist/esm/pkg-version.js +3 -4
  140. package/dist/cjs/pathfinding/Pathfinding.js +245 -263
  141. package/dist/cjs/performance/AssetStreaming.js +561 -635
  142. package/dist/cjs/performance/BenchmarkSuite.js +283 -311
  143. package/dist/cjs/performance/DeltaCompression.js +467 -526
  144. package/dist/cjs/performance/DeterministicPhysics.js +450 -498
  145. package/dist/cjs/performance/ECSOptimization.js +644 -695
  146. package/dist/cjs/performance/GameSaveSystem.js +509 -556
  147. package/dist/cjs/performance/HotReload.js +447 -500
  148. package/dist/cjs/performance/InputRecording.js +511 -561
  149. package/dist/cjs/performance/InterestManagement.js +453 -500
  150. package/dist/cjs/performance/LocalizationRuntime.js +376 -423
  151. package/dist/cjs/performance/MemoryManagement.js +410 -470
  152. package/dist/cjs/performance/ModSupport.js +445 -496
  153. package/dist/cjs/performance/MultiThreadedPhysics.js +400 -443
  154. package/dist/cjs/performance/NetworkPrediction.js +424 -482
  155. package/dist/cjs/performance/ObjectPooling.js +569 -617
  156. package/dist/cjs/performance/Performance.js +174 -190
  157. package/dist/cjs/performance/PerformanceAdvanced.js +614 -637
  158. package/dist/cjs/performance/WebGPURenderer.js +656 -683
  159. package/dist/cjs/physics/PhysicsAdvanced.js +345 -379
  160. package/dist/cjs/physics/PhysicsEngine2D.js +391 -427
  161. package/dist/cjs/plugins/PluginSDK.js +432 -466
  162. package/dist/cjs/plugins/PluginTestKit.js +307 -330
  163. package/dist/cjs/procedural/Procedural.js +243 -254
  164. package/dist/cjs/procedural/WorldBuilding.js +297 -314
  165. package/dist/cjs/quest/QuestSystem.js +975 -932
  166. package/dist/cjs/release/MobileExport.js +157 -163
  167. package/dist/cjs/release/Release.js +225 -238
  168. package/dist/cjs/rendering/Camera2D.js +121 -124
  169. package/dist/cjs/rendering/Renderer2D.js +321 -335
  170. package/dist/cjs/rendering/WebGPURenderPipeline.js +632 -651
  171. package/dist/cjs/runtime3d/Runtime3D.js +359 -378
  172. package/dist/cjs/runtime3d/SceneEditor3D.js +252 -263
  173. package/dist/cjs/scene/SceneManager.js +177 -193
  174. package/dist/cjs/scripting/GraphToAST.js +574 -547
  175. package/dist/cjs/scripting/LanguageExporter.js +254 -279
  176. package/dist/cjs/scripting/NodeGraph.js +546 -570
  177. package/dist/cjs/scripting/ScriptAST.js +31 -39
  178. package/dist/cjs/scripting/VisualScripting2.js +1016 -1065
  179. package/dist/cjs/scripting/exporters/CSharpExporter.js +464 -496
  180. package/dist/cjs/scripting/exporters/GDScriptExporter.js +390 -442
  181. package/dist/cjs/scripting/exporters/LuaExporter.js +406 -447
  182. package/dist/cjs/scripting/exporters/PythonExporter.js +484 -549
  183. package/dist/cjs/scripting/exporters/RustExporter.js +459 -512
  184. package/dist/cjs/scripting/exporters/TypeScriptExporter.js +505 -556
  185. package/dist/cjs/social/Social.js +72 -80
  186. package/dist/cjs/systems/LightingSystem.js +844 -931
  187. package/dist/cjs/systems/ParticleSystem2.js +1447 -1451
  188. package/dist/cjs/systems/PhysicsDebugSystem.js +1070 -1141
  189. package/dist/cjs/systems/TerrainSystem.js +985 -1098
  190. package/dist/cjs/templates/ActionTemplates.js +296 -309
  191. package/dist/cjs/templates/FightingTemplate.js +417 -463
  192. package/dist/cjs/templates/MetroidvaniaTemplate.js +353 -405
  193. package/dist/cjs/templates/PartyTemplates.js +190 -202
  194. package/dist/cjs/templates/PuzzleTemplates.js +245 -261
  195. package/dist/cjs/templates/RPGTemplates.js +160 -178
  196. package/dist/cjs/templates/SportsTemplates.js +237 -250
  197. package/dist/cjs/templates/StrategyTemplates.js +143 -153
  198. package/dist/cjs/templates/SurvivalTemplate.js +336 -380
  199. package/dist/cjs/templates/WaveDefense.js +499 -526
  200. package/dist/cjs/tilemap/Tilemap.js +207 -214
  201. package/dist/cjs/tutorials/TutorialBranching.js +396 -417
  202. package/dist/cjs/tutorials/TutorialEngine.js +888 -931
  203. package/dist/cjs/tutorials/TutorialOverlay.js +602 -640
  204. package/dist/cjs/tutorials/content/Tutorials_T05_T08.js +787 -809
  205. package/dist/cjs/tutorials/content/Tutorials_T09_T11.js +736 -756
  206. package/dist/cjs/tutorials/content/Tutorials_T12_T15.js +754 -778
  207. package/dist/cjs/ui/GameUI.js +295 -312
  208. package/dist/cjs/unity-integration/UnityAssetStore.js +700 -741
  209. package/dist/cjs/unity-integration/UnityImport.js +1066 -1176
  210. package/dist/cjs/unity-integration/UnityLiveLink.js +934 -981
  211. package/dist/cjs/unity-integration/components/UnityAssetStoreBrowser.js +1233 -757
  212. package/dist/cjs/unity-integration/components/UnityProjectBrowser.js +1240 -768
  213. package/dist/cjs/unreal-integration/UnrealImport.js +391 -412
  214. package/dist/cjs/unreal-integration/UnrealLiveLink.js +1102 -1137
  215. package/dist/cjs/unreal-integration/UnrealMarketplace.js +436 -473
  216. package/dist/cjs/unreal-integration/components/UnrealProjectBrowser.js +1150 -767
  217. package/dist/cjs/xr/ARVR.js +167 -175
  218. package/dist/esm/accessibility/Accessibility.js +160 -164
  219. package/dist/esm/ai/AI.js +310 -293
  220. package/dist/esm/ai/BehaviorTree.js +1057 -1112
  221. package/dist/esm/ai/StateMachine.js +709 -755
  222. package/dist/esm/animation/Animation.js +237 -240
  223. package/dist/esm/audio/AudioAdvanced.js +239 -235
  224. package/dist/esm/audio/AudioBridge.js +448 -434
  225. package/dist/esm/audio/AudioManager.js +243 -258
  226. package/dist/esm/build-cloud/BuildOrchestration.js +1071 -1097
  227. package/dist/esm/build-cloud/GodotBuildCloud.js +647 -669
  228. package/dist/esm/build-cloud/UnityBuildCloud.js +571 -609
  229. package/dist/esm/build-cloud/UnrealBuildCloud.js +615 -634
  230. package/dist/esm/core/EventBus.js +52 -55
  231. package/dist/esm/core/GameClock.js +63 -65
  232. package/dist/esm/core/GameConfig.js +77 -78
  233. package/dist/esm/core/GameLoop.js +81 -88
  234. package/dist/esm/core/ServiceLocator.js +63 -64
  235. package/dist/esm/core/Validation.js +82 -81
  236. package/dist/esm/core/math.js +109 -111
  237. package/dist/esm/devtools/DevTools.js +546 -562
  238. package/dist/esm/devtools/DeveloperExperience.js +535 -558
  239. package/dist/esm/devtools/GameplayAnalytics.js +647 -645
  240. package/dist/esm/dialogue/DialogueSystem.js +998 -985
  241. package/dist/esm/docs/DocGenerator.js +342 -363
  242. package/dist/esm/ecs/World.js +358 -370
  243. package/dist/esm/editor/AchievementEditor.js +584 -635
  244. package/dist/esm/editor/AdvancedEditor.js +191 -190
  245. package/dist/esm/editor/AnimationRetargeting.js +700 -740
  246. package/dist/esm/editor/AssetBrowser.js +1078 -1159
  247. package/dist/esm/editor/AssetManager.js +188 -191
  248. package/dist/esm/editor/ConsolePro.js +977 -1060
  249. package/dist/esm/editor/CraftingEditor.js +684 -729
  250. package/dist/esm/editor/DebugTools.js +194 -184
  251. package/dist/esm/editor/DialogueSystem.js +849 -900
  252. package/dist/esm/editor/LeaderboardSystem.js +433 -482
  253. package/dist/esm/editor/NiceGameEditor.js +1908 -1200
  254. package/dist/esm/editor/PrefabSystem.js +777 -837
  255. package/dist/esm/editor/ProfilerPanel.js +654 -699
  256. package/dist/esm/editor/QuestEditor.js +795 -838
  257. package/dist/esm/editor/ReplaySystem.js +591 -633
  258. package/dist/esm/editor/SceneEditor.js +189 -199
  259. package/dist/esm/editor/ScreenshotMode.js +628 -687
  260. package/dist/esm/editor/ShaderGraph.js +1565 -1581
  261. package/dist/esm/editor/TimelineEditor.js +733 -777
  262. package/dist/esm/editor/UndoRedoPro.js +835 -903
  263. package/dist/esm/editor/VRARMode.js +586 -644
  264. package/dist/esm/engine/NiceGameEngine.js +142 -163
  265. package/dist/esm/engine/SaveSystem.js +447 -494
  266. package/dist/esm/enterprise/Enterprise.js +265 -260
  267. package/dist/esm/export/BevyExporter.js +929 -966
  268. package/dist/esm/export/CocosExporter.js +646 -672
  269. package/dist/esm/export/Construct3Exporter.js +785 -793
  270. package/dist/esm/export/DefoldExporter.js +1030 -1068
  271. package/dist/esm/export/GDevelopExporter.js +676 -707
  272. package/dist/esm/export/GameMakerExporter.js +793 -804
  273. package/dist/esm/export/GodotExporter.js +1004 -1044
  274. package/dist/esm/export/MinecraftBedrockExporter.js +575 -577
  275. package/dist/esm/export/MonoGameExporter.js +1267 -1292
  276. package/dist/esm/export/Pico8Exporter.js +768 -811
  277. package/dist/esm/export/PlatformExporter.js +193 -205
  278. package/dist/esm/export/RPGMakerExporter.js +862 -878
  279. package/dist/esm/export/RobloxExporter.js +885 -918
  280. package/dist/esm/export/Solar2DExporter.js +1220 -1255
  281. package/dist/esm/export/ThreeJSExporter.js +1007 -1072
  282. package/dist/esm/export/Tic80Exporter.js +1212 -1266
  283. package/dist/esm/export/UnityExporter.js +1117 -1130
  284. package/dist/esm/export/UnrealExporter.js +891 -918
  285. package/dist/esm/export/WebExporter.js +933 -969
  286. package/dist/esm/export/index.js +86 -71
  287. package/dist/esm/godot-integration/GodotAssetLibrary.js +663 -691
  288. package/dist/esm/godot-integration/GodotImport.js +935 -1026
  289. package/dist/esm/godot-integration/GodotLiveLink.js +918 -944
  290. package/dist/esm/godot-integration/components/GodotProjectBrowser.js +912 -610
  291. package/dist/esm/i18n/I18n.js +871 -899
  292. package/dist/esm/i18n/useTranslation.js +88 -88
  293. package/dist/esm/import/AsepriteImporter.js +637 -715
  294. package/dist/esm/import/DragonBonesImporter.js +417 -460
  295. package/dist/esm/import/GameMakerImporter.js +491 -520
  296. package/dist/esm/import/GodotSceneImporter.js +767 -821
  297. package/dist/esm/import/LDtkImporter.js +415 -453
  298. package/dist/esm/import/Live2DImporter.js +477 -517
  299. package/dist/esm/import/NdgFormat.js +410 -456
  300. package/dist/esm/import/OgmoImporter.js +446 -492
  301. package/dist/esm/import/RPGMakerImporter.js +431 -476
  302. package/dist/esm/import/SceneImporter.js +385 -422
  303. package/dist/esm/import/SpineImporter.js +491 -545
  304. package/dist/esm/import/SpriterImporter.js +570 -612
  305. package/dist/esm/import/TiledMapImporter.js +790 -845
  306. package/dist/esm/import/UnitySceneImporter.js +666 -702
  307. package/dist/esm/import/index.js +247 -258
  308. package/dist/esm/index.js +1332 -188
  309. package/dist/esm/input/GamepadNavigation.js +187 -204
  310. package/dist/esm/input/InputManager.js +401 -420
  311. package/dist/esm/input/useGamepads.js +72 -80
  312. package/dist/esm/integration/IconSprite.js +143 -255
  313. package/dist/esm/inventory/InventorySystem.js +925 -994
  314. package/dist/esm/kids/KidMode.js +1003 -1021
  315. package/dist/esm/kids/KidTools.js +573 -593
  316. package/dist/esm/monetization/Monetization.js +180 -176
  317. package/dist/esm/multiplayer/LocalMultiplayer.js +290 -286
  318. package/dist/esm/multiplayer/MiniGameTypes.js +58 -58
  319. package/dist/esm/native-engine/AnimationSystem.js +735 -805
  320. package/dist/esm/native-engine/AssetPipeline.js +456 -514
  321. package/dist/esm/native-engine/AudioEngine.js +765 -803
  322. package/dist/esm/native-engine/InputSystem.js +1079 -1144
  323. package/dist/esm/native-engine/NetworkingSystem.js +740 -792
  324. package/dist/esm/native-engine/PhysicsEngine.js +585 -606
  325. package/dist/esm/native-engine/RenderingEngine.js +304 -349
  326. package/dist/esm/native-engine/SceneGraph.js +773 -807
  327. package/dist/esm/network/MultiplayerTransport.js +99 -131
  328. package/dist/esm/network/Networking.js +556 -563
  329. package/dist/esm/node_modules/@microsoft/signalr/dist/esm/AbortController.js +22 -28
  330. package/dist/esm/node_modules/@microsoft/signalr/dist/esm/AccessTokenHttpClient.js +41 -47
  331. package/dist/esm/node_modules/@microsoft/signalr/dist/esm/DefaultHttpClient.js +36 -42
  332. package/dist/esm/node_modules/@microsoft/signalr/dist/esm/DefaultReconnectPolicy.js +11 -14
  333. package/dist/esm/node_modules/@microsoft/signalr/dist/esm/Errors.js +111 -134
  334. package/dist/esm/node_modules/@microsoft/signalr/dist/esm/FetchHttpClient.js +132 -157
  335. package/dist/esm/node_modules/@microsoft/signalr/dist/esm/HandshakeProtocol.js +40 -52
  336. package/dist/esm/node_modules/@microsoft/signalr/dist/esm/HeaderNames.js +6 -7
  337. package/dist/esm/node_modules/@microsoft/signalr/dist/esm/HttpClient.js +42 -47
  338. package/dist/esm/node_modules/@microsoft/signalr/dist/esm/HttpConnection.js +496 -571
  339. package/dist/esm/node_modules/@microsoft/signalr/dist/esm/HubConnection.js +828 -952
  340. package/dist/esm/node_modules/@microsoft/signalr/dist/esm/HubConnectionBuilder.js +126 -145
  341. package/dist/esm/node_modules/@microsoft/signalr/dist/esm/IHubProtocol.js +14 -23
  342. package/dist/esm/node_modules/@microsoft/signalr/dist/esm/ILogger.js +12 -25
  343. package/dist/esm/node_modules/@microsoft/signalr/dist/esm/ITransport.js +15 -24
  344. package/dist/esm/node_modules/@microsoft/signalr/dist/esm/JsonHubProtocol.js +109 -120
  345. package/dist/esm/node_modules/@microsoft/signalr/dist/esm/Loggers.js +11 -13
  346. package/dist/esm/node_modules/@microsoft/signalr/dist/esm/LongPollingTransport.js +151 -184
  347. package/dist/esm/node_modules/@microsoft/signalr/dist/esm/MessageBuffer.js +159 -195
  348. package/dist/esm/node_modules/@microsoft/signalr/dist/esm/ServerSentEventsTransport.js +91 -104
  349. package/dist/esm/node_modules/@microsoft/signalr/dist/esm/Subject.js +31 -34
  350. package/dist/esm/node_modules/@microsoft/signalr/dist/esm/TextMessageFormat.js +17 -20
  351. package/dist/esm/node_modules/@microsoft/signalr/dist/esm/Utils.js +230 -248
  352. package/dist/esm/node_modules/@microsoft/signalr/dist/esm/WebSocketTransport.js +136 -156
  353. package/dist/esm/node_modules/@microsoft/signalr/dist/esm/XhrHttpClient.js +77 -84
  354. package/dist/esm/node_modules/@microsoft/signalr/dist/esm/index.js +31 -12
  355. package/dist/esm/node_modules/@microsoft/signalr/dist/esm/pkg-version.js +4 -3
  356. package/dist/esm/pathfinding/Pathfinding.js +249 -262
  357. package/dist/esm/performance/AssetStreaming.js +567 -634
  358. package/dist/esm/performance/BenchmarkSuite.js +285 -310
  359. package/dist/esm/performance/DeltaCompression.js +478 -525
  360. package/dist/esm/performance/DeterministicPhysics.js +479 -497
  361. package/dist/esm/performance/ECSOptimization.js +653 -694
  362. package/dist/esm/performance/GameSaveSystem.js +515 -555
  363. package/dist/esm/performance/HotReload.js +454 -499
  364. package/dist/esm/performance/InputRecording.js +520 -560
  365. package/dist/esm/performance/InterestManagement.js +460 -499
  366. package/dist/esm/performance/LocalizationRuntime.js +382 -422
  367. package/dist/esm/performance/MemoryManagement.js +415 -469
  368. package/dist/esm/performance/ModSupport.js +455 -495
  369. package/dist/esm/performance/MultiThreadedPhysics.js +408 -442
  370. package/dist/esm/performance/NetworkPrediction.js +436 -481
  371. package/dist/esm/performance/ObjectPooling.js +582 -616
  372. package/dist/esm/performance/Performance.js +182 -189
  373. package/dist/esm/performance/PerformanceAdvanced.js +621 -636
  374. package/dist/esm/performance/WebGPURenderer.js +660 -682
  375. package/dist/esm/physics/PhysicsAdvanced.js +359 -378
  376. package/dist/esm/physics/PhysicsEngine2D.js +393 -426
  377. package/dist/esm/plugins/PluginSDK.js +435 -465
  378. package/dist/esm/plugins/PluginTestKit.js +315 -329
  379. package/dist/esm/procedural/Procedural.js +248 -253
  380. package/dist/esm/procedural/WorldBuilding.js +316 -313
  381. package/dist/esm/quest/QuestSystem.js +982 -931
  382. package/dist/esm/release/MobileExport.js +163 -162
  383. package/dist/esm/release/Release.js +234 -237
  384. package/dist/esm/rendering/Camera2D.js +122 -123
  385. package/dist/esm/rendering/Renderer2D.js +323 -334
  386. package/dist/esm/rendering/WebGPURenderPipeline.js +647 -650
  387. package/dist/esm/runtime3d/Runtime3D.js +368 -377
  388. package/dist/esm/runtime3d/SceneEditor3D.js +268 -262
  389. package/dist/esm/scene/SceneManager.js +178 -192
  390. package/dist/esm/scripting/GraphToAST.js +576 -546
  391. package/dist/esm/scripting/LanguageExporter.js +263 -278
  392. package/dist/esm/scripting/NodeGraph.js +550 -569
  393. package/dist/esm/scripting/ScriptAST.js +45 -38
  394. package/dist/esm/scripting/VisualScripting2.js +1025 -1064
  395. package/dist/esm/scripting/exporters/CSharpExporter.js +465 -495
  396. package/dist/esm/scripting/exporters/GDScriptExporter.js +391 -441
  397. package/dist/esm/scripting/exporters/LuaExporter.js +407 -446
  398. package/dist/esm/scripting/exporters/PythonExporter.js +485 -548
  399. package/dist/esm/scripting/exporters/RustExporter.js +460 -511
  400. package/dist/esm/scripting/exporters/TypeScriptExporter.js +506 -555
  401. package/dist/esm/social/Social.js +77 -79
  402. package/dist/esm/systems/LightingSystem.js +855 -930
  403. package/dist/esm/systems/ParticleSystem2.js +1453 -1450
  404. package/dist/esm/systems/PhysicsDebugSystem.js +1078 -1140
  405. package/dist/esm/systems/TerrainSystem.js +996 -1097
  406. package/dist/esm/templates/ActionTemplates.js +307 -308
  407. package/dist/esm/templates/FightingTemplate.js +439 -462
  408. package/dist/esm/templates/MetroidvaniaTemplate.js +391 -404
  409. package/dist/esm/templates/PartyTemplates.js +206 -201
  410. package/dist/esm/templates/PuzzleTemplates.js +260 -260
  411. package/dist/esm/templates/RPGTemplates.js +172 -177
  412. package/dist/esm/templates/SportsTemplates.js +251 -249
  413. package/dist/esm/templates/StrategyTemplates.js +158 -152
  414. package/dist/esm/templates/SurvivalTemplate.js +367 -379
  415. package/dist/esm/templates/WaveDefense.js +501 -525
  416. package/dist/esm/tilemap/Tilemap.js +209 -213
  417. package/dist/esm/tutorials/TutorialBranching.js +399 -416
  418. package/dist/esm/tutorials/TutorialEngine.js +893 -930
  419. package/dist/esm/tutorials/TutorialOverlay.js +603 -639
  420. package/dist/esm/tutorials/content/Tutorials_T05_T08.js +792 -808
  421. package/dist/esm/tutorials/content/Tutorials_T09_T11.js +740 -755
  422. package/dist/esm/tutorials/content/Tutorials_T12_T15.js +759 -777
  423. package/dist/esm/ui/GameUI.js +296 -311
  424. package/dist/esm/unity-integration/UnityAssetStore.js +704 -740
  425. package/dist/esm/unity-integration/UnityImport.js +1071 -1175
  426. package/dist/esm/unity-integration/UnityLiveLink.js +938 -980
  427. package/dist/esm/unity-integration/components/UnityAssetStoreBrowser.js +1234 -756
  428. package/dist/esm/unity-integration/components/UnityProjectBrowser.js +1241 -767
  429. package/dist/esm/unreal-integration/UnrealImport.js +395 -411
  430. package/dist/esm/unreal-integration/UnrealLiveLink.js +1105 -1136
  431. package/dist/esm/unreal-integration/UnrealMarketplace.js +442 -472
  432. package/dist/esm/unreal-integration/components/UnrealProjectBrowser.js +1151 -766
  433. package/dist/esm/xr/ARVR.js +181 -174
  434. package/package.json +7 -12
@@ -1,1279 +1,1244 @@
1
- import { PlatformExporter } from './PlatformExporter.js';
2
-
3
- /* ────────────────────────────────────────────────────────────────
4
- Solar2D (Corona SDK) Exporter
5
-
6
- Exports Nice2Dev projects to Solar2D format:
7
- - Main project files (main.lua, config.lua, build.settings)
8
- - Scene modules
9
- - Lua scripts
10
- - Asset management
11
- ──────────────────────────────────────────────────────────────── */
12
- /* ── Exporter Implementation ──────────────────────────────────── */
1
+ import { PlatformExporter } from "./PlatformExporter.js";
13
2
  class Solar2DExporter extends PlatformExporter {
14
- constructor() {
15
- super(...arguments);
16
- this.platformId = 'solar2d';
17
- this.platformInfo = {
18
- id: 'solar2d',
19
- name: 'Solar2D',
20
- description: 'Solar2D (formerly Corona SDK) - Cross-platform 2D game engine',
21
- website: 'https://solar2d.com/',
22
- features: ['2d-rendering', 'physics-2d', 'audio', 'particles', 'ui-system', 'animation'],
23
- supportedAssets: [
24
- 'texture',
25
- 'audio',
26
- 'tilemap',
27
- 'animation',
28
- 'prefab',
29
- 'scene',
30
- 'data',
31
- 'font',
32
- ],
33
- exportFormats: ['.lua', '.json', '.settings'],
34
- };
3
+ constructor() {
4
+ super(...arguments);
5
+ this.platformId = "solar2d";
6
+ this.platformInfo = {
7
+ id: "solar2d",
8
+ name: "Solar2D",
9
+ description: "Solar2D (formerly Corona SDK) - Cross-platform 2D game engine",
10
+ website: "https://solar2d.com/",
11
+ features: ["2d-rendering", "physics-2d", "audio", "particles", "ui-system", "animation"],
12
+ supportedAssets: [
13
+ "texture",
14
+ "audio",
15
+ "tilemap",
16
+ "animation",
17
+ "prefab",
18
+ "scene",
19
+ "data",
20
+ "font"
21
+ ],
22
+ exportFormats: [".lua", ".json", ".settings"]
23
+ };
24
+ }
25
+ async doExport(project, options) {
26
+ options.platformOptions ?? {};
27
+ await this.generateConfigLua(project, options);
28
+ await this.generateBuildSettings(project, options);
29
+ await this.generateMainLua(project, options);
30
+ await this.generateUtilityModules(project, options);
31
+ for (const scene of project.scenes) {
32
+ await this.exportScene(scene, project, options);
35
33
  }
36
- async doExport(project, options) {
37
- options.platformOptions ?? {};
38
- // Generate config.lua
39
- await this.generateConfigLua(project, options);
40
- // Generate build.settings
41
- await this.generateBuildSettings(project, options);
42
- // Generate main.lua
43
- await this.generateMainLua(project, options);
44
- // Generate utility modules
45
- await this.generateUtilityModules(project, options);
46
- // Generate scenes
47
- for (const scene of project.scenes) {
48
- await this.exportScene(scene, project, options);
49
- }
50
- // Generate prefabs
51
- for (const prefab of project.prefabs) {
52
- await this.exportPrefab(prefab, options);
53
- }
54
- // Generate README
55
- await this.generateReadme(project, options);
34
+ for (const prefab of project.prefabs) {
35
+ await this.exportPrefab(prefab, options);
56
36
  }
57
- /* ── Config Lua ─────────────────────────────────────────────── */
58
- async generateConfigLua(project, options) {
59
- const platformOpts = options.platformOptions ?? {};
60
- const scale = platformOpts.scale ?? 'letterbox';
61
- const configLua = `-- Project: ${project.name}
62
- -- Generated from Nice2Dev
63
-
64
- -- config.lua - Application configuration
65
-
66
- local aspectRatio = display.pixelHeight / display.pixelWidth
67
-
68
- application = {
69
- content = {
70
- width = ${scale === 'none' ? 'display.pixelWidth' : project.settings.resolution.width},
71
- height = ${scale === 'none' ? 'display.pixelHeight' : project.settings.resolution.height},
72
- scale = "${scale}",
73
- fps = ${project.settings.targetFrameRate ?? 60},
74
-
75
- -- Dynamic content scaling
76
- imageSuffix = {
77
- ["@2x"] = 1.5,
78
- ["@4x"] = 3.0,
79
- },
80
- },
81
-
82
- -- License configuration
83
- license = {
84
- google = {
85
- key = "YOUR_GOOGLE_LICENSE_KEY",
86
- },
87
- },
88
-
89
- -- Shader precision (optional)
90
- shader = {
91
- precisionHint = "highp",
92
- },
93
- }
94
-
95
- -- Letterbox scaling adjustments
96
- if application.content.scale == "letterbox" then
97
- if aspectRatio > 1.5 then
98
- -- Taller devices (iPad-like)
99
- application.content.height = math.ceil(application.content.width * aspectRatio)
100
- end
101
- end
37
+ await this.generateReadme(project, options);
38
+ }
39
+ /* ── Config Lua ─────────────────────────────────────────────── */
40
+ async generateConfigLua(project, options) {
41
+ const platformOpts = options.platformOptions ?? {};
42
+ const scale = platformOpts.scale ?? "letterbox";
43
+ const configLua = `-- Project: ${project.name}
44
+ -- Generated from Nice2Dev
45
+
46
+ -- config.lua - Application configuration
47
+
48
+ local aspectRatio = display.pixelHeight / display.pixelWidth
49
+
50
+ application = {
51
+ content = {
52
+ width = ${scale === "none" ? "display.pixelWidth" : project.settings.resolution.width},
53
+ height = ${scale === "none" ? "display.pixelHeight" : project.settings.resolution.height},
54
+ scale = "${scale}",
55
+ fps = ${project.settings.targetFrameRate ?? 60},
56
+
57
+ -- Dynamic content scaling
58
+ imageSuffix = {
59
+ ["@2x"] = 1.5,
60
+ ["@4x"] = 3.0,
61
+ },
62
+ },
63
+
64
+ -- License configuration
65
+ license = {
66
+ google = {
67
+ key = "YOUR_GOOGLE_LICENSE_KEY",
68
+ },
69
+ },
70
+
71
+ -- Shader precision (optional)
72
+ shader = {
73
+ precisionHint = "highp",
74
+ },
75
+ }
76
+
77
+ -- Letterbox scaling adjustments
78
+ if application.content.scale == "letterbox" then
79
+ if aspectRatio > 1.5 then
80
+ -- Taller devices (iPad-like)
81
+ application.content.height = math.ceil(application.content.width * aspectRatio)
82
+ end
83
+ end
102
84
  `;
103
- this.addTextFile('config.lua', configLua);
104
- }
105
- /* ── Build Settings ─────────────────────────────────────────── */
106
- async generateBuildSettings(project, options) {
107
- const safeName = (options.projectName ?? project.name)
108
- .toLowerCase()
109
- .replace(/[^a-z0-9_]/g, '_');
110
- const platformOpts = options.platformOptions ?? {};
111
- const buildSettings = `-- Build settings for ${project.name}
112
- -- Generated from Nice2Dev
113
-
114
- settings = {
115
- -- Application orientation(s)
116
- orientation = {
117
- default = "landscapeRight",
118
- supported = { "landscapeLeft", "landscapeRight" },
119
- },
120
-
121
- -- Exclude files from build
122
- excludeFiles = {
123
- all = { "*.psd", "*.txt", "*.md", "*.json" },
124
- ios = { "Icon-*dpi.png", "*.ogg" },
125
- android = { "Icon.png", "Icon-Small-*.png", "Icon*@2x.png", "*.aiff" },
126
- },
127
-
128
- -- iOS settings
129
- iphone = {
130
- plist = {
131
- UIStatusBarHidden = true,
132
- UILaunchStoryboardName = "LaunchScreen",
133
- UIApplicationExitsOnSuspend = false,
134
- CFBundleDisplayName = "${project.name}",
135
- CFBundleIdentifier = "com.nice2dev.${safeName}",
136
- CFBundleName = "${project.name}",
137
- CFBundleVersion = "${project.version}",
138
- CFBundleShortVersionString = "${project.version}",
139
- ITSAppUsesNonExemptEncryption = false,
140
- NSAppTransportSecurity = {
141
- NSAllowsArbitraryLoads = true,
142
- },
143
- },
144
- xcassets = "Images.xcassets",
145
- entitlements = {
146
- ["com.apple.developer.game-center"] = true,
147
- },
148
- },
149
-
150
- -- Android settings
151
- android = {
152
- versionCode = "${project.version.replace(/\./g, '')}1",
153
- usesPermissions = {
154
- "android.permission.INTERNET",
155
- "android.permission.WRITE_EXTERNAL_STORAGE",
156
- "android.permission.VIBRATE",
157
- },
158
- supportsScreens = {
159
- smallScreens = true,
160
- normalScreens = true,
161
- largeScreens = true,
162
- xlargeScreens = true,
163
- },
164
- applicationChildElements = {
165
- [[
166
- <meta-data android:name="com.google.android.gms.version"
167
- android:value="@integer/google_play_services_version" />
168
- ]],
169
- },
170
- usesFeatures = {},
171
- },
172
-
173
- -- Windows settings
174
- win32 = {
175
- singleInstance = true,
176
- preferenceStorage = "registry",
177
- },
178
-
179
- -- macOS settings
180
- osx = {
181
- bundleIdentifier = "com.nice2dev.${safeName}",
182
- retinaSupport = true,
183
- },
184
-
185
- -- HTML5 settings
186
- html5 = {
187
- fps = ${project.settings.targetFrameRate ?? 60},
188
- width = ${project.settings.resolution.width},
189
- height = ${project.settings.resolution.height},
190
- preferWebGL = true,
191
- },
192
-
193
- -- Plugins
194
- plugins = {
195
- ${platformOpts.pluginStubs
196
- ? ` ["plugin.Bytedance"] = { publisherId = "social.nicetodrive" },
197
- ["plugin.ads.mediator"] = { publisherId = "com.coronalabs" },`
198
- : ''}
199
- },
200
-
201
- -- Splash screen
202
- splashScreen = {
203
- enable = true,
204
- image = "splash.png",
205
- },
206
- }
85
+ this.addTextFile("config.lua", configLua);
86
+ }
87
+ /* ── Build Settings ─────────────────────────────────────────── */
88
+ async generateBuildSettings(project, options) {
89
+ const safeName = (options.projectName ?? project.name).toLowerCase().replace(/[^a-z0-9_]/g, "_");
90
+ const platformOpts = options.platformOptions ?? {};
91
+ const buildSettings = `-- Build settings for ${project.name}
92
+ -- Generated from Nice2Dev
93
+
94
+ settings = {
95
+ -- Application orientation(s)
96
+ orientation = {
97
+ default = "landscapeRight",
98
+ supported = { "landscapeLeft", "landscapeRight" },
99
+ },
100
+
101
+ -- Exclude files from build
102
+ excludeFiles = {
103
+ all = { "*.psd", "*.txt", "*.md", "*.json" },
104
+ ios = { "Icon-*dpi.png", "*.ogg" },
105
+ android = { "Icon.png", "Icon-Small-*.png", "Icon*@2x.png", "*.aiff" },
106
+ },
107
+
108
+ -- iOS settings
109
+ iphone = {
110
+ plist = {
111
+ UIStatusBarHidden = true,
112
+ UILaunchStoryboardName = "LaunchScreen",
113
+ UIApplicationExitsOnSuspend = false,
114
+ CFBundleDisplayName = "${project.name}",
115
+ CFBundleIdentifier = "com.nice2dev.${safeName}",
116
+ CFBundleName = "${project.name}",
117
+ CFBundleVersion = "${project.version}",
118
+ CFBundleShortVersionString = "${project.version}",
119
+ ITSAppUsesNonExemptEncryption = false,
120
+ NSAppTransportSecurity = {
121
+ NSAllowsArbitraryLoads = true,
122
+ },
123
+ },
124
+ xcassets = "Images.xcassets",
125
+ entitlements = {
126
+ ["com.apple.developer.game-center"] = true,
127
+ },
128
+ },
129
+
130
+ -- Android settings
131
+ android = {
132
+ versionCode = "${project.version.replace(/\./g, "")}1",
133
+ usesPermissions = {
134
+ "android.permission.INTERNET",
135
+ "android.permission.WRITE_EXTERNAL_STORAGE",
136
+ "android.permission.VIBRATE",
137
+ },
138
+ supportsScreens = {
139
+ smallScreens = true,
140
+ normalScreens = true,
141
+ largeScreens = true,
142
+ xlargeScreens = true,
143
+ },
144
+ applicationChildElements = {
145
+ [[
146
+ <meta-data android:name="com.google.android.gms.version"
147
+ android:value="@integer/google_play_services_version" />
148
+ ]],
149
+ },
150
+ usesFeatures = {},
151
+ },
152
+
153
+ -- Windows settings
154
+ win32 = {
155
+ singleInstance = true,
156
+ preferenceStorage = "registry",
157
+ },
158
+
159
+ -- macOS settings
160
+ osx = {
161
+ bundleIdentifier = "com.nice2dev.${safeName}",
162
+ retinaSupport = true,
163
+ },
164
+
165
+ -- HTML5 settings
166
+ html5 = {
167
+ fps = ${project.settings.targetFrameRate ?? 60},
168
+ width = ${project.settings.resolution.width},
169
+ height = ${project.settings.resolution.height},
170
+ preferWebGL = true,
171
+ },
172
+
173
+ -- Plugins
174
+ plugins = {
175
+ ${platformOpts.pluginStubs ? ` ["plugin.Bytedance"] = { publisherId = "social.nicetodrive" },
176
+ ["plugin.ads.mediator"] = { publisherId = "com.coronalabs" },` : ""}
177
+ },
178
+
179
+ -- Splash screen
180
+ splashScreen = {
181
+ enable = true,
182
+ image = "splash.png",
183
+ },
184
+ }
207
185
  `;
208
- this.addTextFile('build.settings', buildSettings);
209
- }
210
- /* ── Main Lua ───────────────────────────────────────────────── */
211
- async generateMainLua(project, options) {
212
- const platformOpts = options.platformOptions ?? {};
213
- const usePhysics = platformOpts.usePhysics !== false;
214
- platformOpts.useComposer !== false;
215
- const firstScene = project.scenes[0];
216
- const firstSceneName = firstScene
217
- ? firstScene.name.toLowerCase().replace(/[^a-z0-9_]/g, '_')
218
- : 'main_scene';
219
- const mainLua = `-- ${project.name}
220
- -- Main entry point
221
- -- Generated from Nice2Dev
222
-
223
- ---------------------------------------------------------------------------------
224
- -- Modules
225
- ---------------------------------------------------------------------------------
226
- local composer = require("composer")
227
- local physics = require("physics")
228
-
229
- -- Game modules
230
- local GameManager = require("modules.game_manager")
231
- local Utils = require("modules.utils")
232
- local Events = require("modules.events")
233
-
234
- ---------------------------------------------------------------------------------
235
- -- Configuration
236
- ---------------------------------------------------------------------------------
237
- display.setStatusBar(display.HiddenStatusBar)
238
- display.setDefault("background", 0, 0, 0)
239
-
240
- -- Multitouch
241
- system.activate("multitouch")
242
-
243
- -- Random seed
244
- math.randomseed(os.time())
245
-
246
- ---------------------------------------------------------------------------------
247
- -- Physics Setup
248
- ---------------------------------------------------------------------------------
249
- ${usePhysics
250
- ? `physics.start()
251
- physics.setGravity(${project.settings.physics.gravity.x}, ${project.settings.physics.gravity.y * -1})
252
- physics.setDrawMode("normal") -- debug: "hybrid" or "debug"
253
- physics.setScale(${project.settings.physics.scale ?? 30})`
254
- : '-- Physics disabled'}
255
-
256
- ---------------------------------------------------------------------------------
257
- -- Global Game State
258
- ---------------------------------------------------------------------------------
259
- _G.GAME = {
260
- name = "${project.name}",
261
- version = "${project.version}",
262
- settings = {
263
- width = ${project.settings.resolution.width},
264
- height = ${project.settings.resolution.height},
265
- masterVolume = ${project.settings.audio.masterVolume},
266
- },
267
- state = {
268
- isPaused = false,
269
- currentScene = nil,
270
- score = 0,
271
- level = 1,
272
- },
273
- entities = {},
274
- }
275
-
276
- ---------------------------------------------------------------------------------
277
- -- Initialize Game Manager
278
- ---------------------------------------------------------------------------------
279
- GameManager.init()
280
-
281
- ---------------------------------------------------------------------------------
282
- -- Global Key Listener (for testing/debug)
283
- ---------------------------------------------------------------------------------
284
- local function onKeyEvent(event)
285
- if event.phase == "up" then
286
- if event.keyName == "escape" or event.keyName == "back" then
287
- -- Handle back button
288
- if composer.getSceneName("current") ~= "${firstSceneName}" then
289
- composer.gotoScene("scenes.${firstSceneName}", { effect = "fade", time = 300 })
290
- else
291
- native.requestExit()
292
- end
293
- return true
294
- elseif event.keyName == "p" then
295
- -- Toggle pause
296
- _G.GAME.state.isPaused = not _G.GAME.state.isPaused
297
- Events.dispatch("game:pause", { isPaused = _G.GAME.state.isPaused })
298
- end
299
- end
300
- return false
301
- end
302
- Runtime:addEventListener("key", onKeyEvent)
303
-
304
- ---------------------------------------------------------------------------------
305
- -- Start Game
306
- ---------------------------------------------------------------------------------
307
- print("[Nice2Dev] Starting ${project.name} v${project.version}")
308
-
309
- -- Go to first scene
310
- composer.gotoScene("scenes.${firstSceneName}", {
311
- effect = "fade",
312
- time = 500,
313
- })
186
+ this.addTextFile("build.settings", buildSettings);
187
+ }
188
+ /* ── Main Lua ───────────────────────────────────────────────── */
189
+ async generateMainLua(project, options) {
190
+ const platformOpts = options.platformOptions ?? {};
191
+ const usePhysics = platformOpts.usePhysics !== false;
192
+ platformOpts.useComposer !== false;
193
+ const firstScene = project.scenes[0];
194
+ const firstSceneName = firstScene ? firstScene.name.toLowerCase().replace(/[^a-z0-9_]/g, "_") : "main_scene";
195
+ const mainLua = `-- ${project.name}
196
+ -- Main entry point
197
+ -- Generated from Nice2Dev
198
+
199
+ ---------------------------------------------------------------------------------
200
+ -- Modules
201
+ ---------------------------------------------------------------------------------
202
+ local composer = require("composer")
203
+ local physics = require("physics")
204
+
205
+ -- Game modules
206
+ local GameManager = require("modules.game_manager")
207
+ local Utils = require("modules.utils")
208
+ local Events = require("modules.events")
209
+
210
+ ---------------------------------------------------------------------------------
211
+ -- Configuration
212
+ ---------------------------------------------------------------------------------
213
+ display.setStatusBar(display.HiddenStatusBar)
214
+ display.setDefault("background", 0, 0, 0)
215
+
216
+ -- Multitouch
217
+ system.activate("multitouch")
218
+
219
+ -- Random seed
220
+ math.randomseed(os.time())
221
+
222
+ ---------------------------------------------------------------------------------
223
+ -- Physics Setup
224
+ ---------------------------------------------------------------------------------
225
+ ${usePhysics ? `physics.start()
226
+ physics.setGravity(${project.settings.physics.gravity.x}, ${project.settings.physics.gravity.y * -1})
227
+ physics.setDrawMode("normal") -- debug: "hybrid" or "debug"
228
+ physics.setScale(${project.settings.physics.scale ?? 30})` : "-- Physics disabled"}
229
+
230
+ ---------------------------------------------------------------------------------
231
+ -- Global Game State
232
+ ---------------------------------------------------------------------------------
233
+ _G.GAME = {
234
+ name = "${project.name}",
235
+ version = "${project.version}",
236
+ settings = {
237
+ width = ${project.settings.resolution.width},
238
+ height = ${project.settings.resolution.height},
239
+ masterVolume = ${project.settings.audio.masterVolume},
240
+ },
241
+ state = {
242
+ isPaused = false,
243
+ currentScene = nil,
244
+ score = 0,
245
+ level = 1,
246
+ },
247
+ entities = {},
248
+ }
249
+
250
+ ---------------------------------------------------------------------------------
251
+ -- Initialize Game Manager
252
+ ---------------------------------------------------------------------------------
253
+ GameManager.init()
254
+
255
+ ---------------------------------------------------------------------------------
256
+ -- Global Key Listener (for testing/debug)
257
+ ---------------------------------------------------------------------------------
258
+ local function onKeyEvent(event)
259
+ if event.phase == "up" then
260
+ if event.keyName == "escape" or event.keyName == "back" then
261
+ -- Handle back button
262
+ if composer.getSceneName("current") ~= "${firstSceneName}" then
263
+ composer.gotoScene("scenes.${firstSceneName}", { effect = "fade", time = 300 })
264
+ else
265
+ native.requestExit()
266
+ end
267
+ return true
268
+ elseif event.keyName == "p" then
269
+ -- Toggle pause
270
+ _G.GAME.state.isPaused = not _G.GAME.state.isPaused
271
+ Events.dispatch("game:pause", { isPaused = _G.GAME.state.isPaused })
272
+ end
273
+ end
274
+ return false
275
+ end
276
+ Runtime:addEventListener("key", onKeyEvent)
277
+
278
+ ---------------------------------------------------------------------------------
279
+ -- Start Game
280
+ ---------------------------------------------------------------------------------
281
+ print("[Nice2Dev] Starting ${project.name} v${project.version}")
282
+
283
+ -- Go to first scene
284
+ composer.gotoScene("scenes.${firstSceneName}", {
285
+ effect = "fade",
286
+ time = 500,
287
+ })
314
288
  `;
315
- this.addTextFile('main.lua', mainLua);
289
+ this.addTextFile("main.lua", mainLua);
290
+ }
291
+ /* ── Utility Modules ────────────────────────────────────────── */
292
+ async generateUtilityModules(_project, _options) {
293
+ const gameManagerLua = `-- Game Manager Module
294
+ -- Central game state and utilities
295
+ -- Generated from Nice2Dev
296
+
297
+ local M = {}
298
+
299
+ -- Dependencies
300
+ local Events = require("modules.events")
301
+ local Utils = require("modules.utils")
302
+
303
+ -- Private state
304
+ local state = {
305
+ entities = {},
306
+ pools = {},
307
+ timers = {},
308
+ audioChannels = {},
309
+ }
310
+
311
+ -- Initialize game manager
312
+ function M.init()
313
+ print("[GameManager] Initializing...")
314
+
315
+ -- Set up audio channels
316
+ audio.setVolume(_G.GAME.settings.masterVolume)
317
+
318
+ -- Create object pools
319
+ state.pools = {}
320
+
321
+ print("[GameManager] Ready")
322
+ end
323
+
324
+ -- Entity management
325
+ function M.registerEntity(entity)
326
+ if entity and entity.id then
327
+ state.entities[entity.id] = entity
328
+ Events.dispatch("entity:registered", { entity = entity })
329
+ end
330
+ end
331
+
332
+ function M.unregisterEntity(entityId)
333
+ if state.entities[entityId] then
334
+ state.entities[entityId] = nil
335
+ Events.dispatch("entity:unregistered", { id = entityId })
336
+ end
337
+ end
338
+
339
+ function M.getEntity(entityId)
340
+ return state.entities[entityId]
341
+ end
342
+
343
+ function M.getEntitiesByTag(tag)
344
+ local result = {}
345
+ for id, entity in pairs(state.entities) do
346
+ if entity.tags and Utils.tableContains(entity.tags, tag) then
347
+ table.insert(result, entity)
348
+ end
349
+ end
350
+ return result
351
+ end
352
+
353
+ -- Object pooling
354
+ function M.createPool(name, factory, initialSize)
355
+ initialSize = initialSize or 10
356
+ state.pools[name] = {
357
+ factory = factory,
358
+ available = {},
359
+ inUse = {},
316
360
  }
317
- /* ── Utility Modules ────────────────────────────────────────── */
318
- async generateUtilityModules(_project, _options) {
319
- // Game Manager
320
- const gameManagerLua = `-- Game Manager Module
321
- -- Central game state and utilities
322
- -- Generated from Nice2Dev
323
-
324
- local M = {}
325
-
326
- -- Dependencies
327
- local Events = require("modules.events")
328
- local Utils = require("modules.utils")
329
-
330
- -- Private state
331
- local state = {
332
- entities = {},
333
- pools = {},
334
- timers = {},
335
- audioChannels = {},
336
- }
337
-
338
- -- Initialize game manager
339
- function M.init()
340
- print("[GameManager] Initializing...")
341
-
342
- -- Set up audio channels
343
- audio.setVolume(_G.GAME.settings.masterVolume)
344
-
345
- -- Create object pools
346
- state.pools = {}
347
-
348
- print("[GameManager] Ready")
349
- end
350
-
351
- -- Entity management
352
- function M.registerEntity(entity)
353
- if entity and entity.id then
354
- state.entities[entity.id] = entity
355
- Events.dispatch("entity:registered", { entity = entity })
356
- end
357
- end
358
-
359
- function M.unregisterEntity(entityId)
360
- if state.entities[entityId] then
361
- state.entities[entityId] = nil
362
- Events.dispatch("entity:unregistered", { id = entityId })
363
- end
364
- end
365
-
366
- function M.getEntity(entityId)
367
- return state.entities[entityId]
368
- end
369
-
370
- function M.getEntitiesByTag(tag)
371
- local result = {}
372
- for id, entity in pairs(state.entities) do
373
- if entity.tags and Utils.tableContains(entity.tags, tag) then
374
- table.insert(result, entity)
375
- end
376
- end
377
- return result
378
- end
379
-
380
- -- Object pooling
381
- function M.createPool(name, factory, initialSize)
382
- initialSize = initialSize or 10
383
- state.pools[name] = {
384
- factory = factory,
385
- available = {},
386
- inUse = {},
387
- }
388
-
389
- for i = 1, initialSize do
390
- local obj = factory()
391
- obj.isVisible = false
392
- table.insert(state.pools[name].available, obj)
393
- end
394
- end
395
-
396
- function M.getFromPool(name)
397
- local pool = state.pools[name]
398
- if not pool then return nil end
399
-
400
- local obj = table.remove(pool.available)
401
- if not obj then
402
- obj = pool.factory()
403
- end
404
-
405
- obj.isVisible = true
406
- table.insert(pool.inUse, obj)
407
- return obj
408
- end
409
-
410
- function M.returnToPool(name, obj)
411
- local pool = state.pools[name]
412
- if not pool then return end
413
-
414
- obj.isVisible = false
415
- for i, inUseObj in ipairs(pool.inUse) do
416
- if inUseObj == obj then
417
- table.remove(pool.inUse, i)
418
- break
419
- end
420
- end
421
- table.insert(pool.available, obj)
422
- end
423
-
424
- -- Audio helpers
425
- function M.playSound(filename, options)
426
- options = options or {}
427
- local sound = audio.loadSound("sounds/" .. filename)
428
- local channel = audio.play(sound, {
429
- channel = options.channel,
430
- loops = options.loops or 0,
431
- onComplete = options.onComplete,
432
- })
433
- return channel
434
- end
435
-
436
- function M.playMusic(filename, options)
437
- options = options or {}
438
- local music = audio.loadStream("music/" .. filename)
439
- local channel = audio.play(music, {
440
- channel = 1,
441
- loops = options.loops or -1,
442
- fadein = options.fadein or 0,
443
- })
444
- state.audioChannels.music = channel
445
- return channel
446
- end
447
-
448
- function M.stopMusic(fadeout)
449
- if state.audioChannels.music then
450
- if fadeout and fadeout > 0 then
451
- audio.fade({
452
- channel = state.audioChannels.music,
453
- time = fadeout,
454
- volume = 0,
455
- })
456
- timer.performWithDelay(fadeout, function()
457
- audio.stop(state.audioChannels.music)
458
- end)
459
- else
460
- audio.stop(state.audioChannels.music)
461
- end
462
- end
463
- end
464
-
465
- -- Pause/Resume
466
- function M.pause()
467
- _G.GAME.state.isPaused = true
468
- physics.pause()
469
- Events.dispatch("game:pause", { isPaused = true })
470
- end
471
-
472
- function M.resume()
473
- _G.GAME.state.isPaused = false
474
- physics.start()
475
- Events.dispatch("game:pause", { isPaused = false })
476
- end
477
-
478
- -- Cleanup
479
- function M.cleanup()
480
- -- Clear entities
481
- for id, _ in pairs(state.entities) do
482
- state.entities[id] = nil
483
- end
484
-
485
- -- Clear pools
486
- for name, pool in pairs(state.pools) do
487
- for _, obj in ipairs(pool.available) do
488
- display.remove(obj)
489
- end
490
- for _, obj in ipairs(pool.inUse) do
491
- display.remove(obj)
492
- end
493
- state.pools[name] = nil
494
- end
495
- end
496
-
497
- return M
498
- `;
499
- this.addTextFile('modules/game_manager.lua', gameManagerLua);
500
- // Utils
501
- const utilsLua = `-- Utils Module
502
- -- Common utility functions
503
- -- Generated from Nice2Dev
504
-
505
- local M = {}
506
-
507
- -- Math utilities
508
- function M.lerp(a, b, t)
509
- return a + (b - a) * math.max(0, math.min(1, t))
510
- end
511
-
512
- function M.clamp(value, min, max)
513
- return math.max(min, math.min(max, value))
514
- end
515
-
516
- function M.randomFloat(min, max)
517
- return min + math.random() * (max - min)
518
- end
519
-
520
- function M.randomInt(min, max)
521
- return math.random(min, max)
522
- end
523
-
524
- function M.distance(x1, y1, x2, y2)
525
- local dx = x2 - x1
526
- local dy = y2 - y1
527
- return math.sqrt(dx * dx + dy * dy)
528
- end
529
-
530
- function M.angle(x1, y1, x2, y2)
531
- return math.atan2(y2 - y1, x2 - x1)
532
- end
533
-
534
- function M.pointInRect(px, py, rx, ry, rw, rh)
535
- return px >= rx and px <= rx + rw and py >= ry and py <= ry + rh
536
- end
537
-
538
- function M.rectsOverlap(r1x, r1y, r1w, r1h, r2x, r2y, r2w, r2h)
539
- return r1x < r2x + r2w and
540
- r1x + r1w > r2x and
541
- r1y < r2y + r2h and
542
- r1y + r1h > r2y
543
- end
544
-
545
- -- Table utilities
546
- function M.tableContains(tbl, value)
547
- for _, v in ipairs(tbl) do
548
- if v == value then return true end
549
- end
550
- return false
551
- end
552
-
553
- function M.tableCopy(tbl)
554
- local copy = {}
555
- for k, v in pairs(tbl) do
556
- if type(v) == "table" then
557
- copy[k] = M.tableCopy(v)
558
- else
559
- copy[k] = v
560
- end
561
- end
562
- return copy
563
- end
564
-
565
- function M.tableLength(tbl)
566
- local count = 0
567
- for _ in pairs(tbl) do count = count + 1 end
568
- return count
569
- end
570
-
571
- function M.tableKeys(tbl)
572
- local keys = {}
573
- for k in pairs(tbl) do
574
- table.insert(keys, k)
575
- end
576
- return keys
577
- end
578
-
579
- function M.shuffleTable(tbl)
580
- for i = #tbl, 2, -1 do
581
- local j = math.random(i)
582
- tbl[i], tbl[j] = tbl[j], tbl[i]
583
- end
584
- return tbl
585
- end
586
-
587
- -- String utilities
588
- function M.split(str, delimiter)
589
- local result = {}
590
- for match in (str .. delimiter):gmatch("(.-)" .. delimiter) do
591
- table.insert(result, match)
592
- end
593
- return result
594
- end
595
-
596
- function M.trim(str)
597
- return str:match("^%s*(.-)%s*$")
598
- end
599
-
600
- -- Timer helpers
601
- function M.setTimeout(callback, delay)
602
- return timer.performWithDelay(delay, callback)
603
- end
604
-
605
- function M.setInterval(callback, interval)
606
- return timer.performWithDelay(interval, callback, 0)
607
- end
608
-
609
- function M.clearTimer(timerHandle)
610
- if timerHandle then
611
- timer.cancel(timerHandle)
612
- end
613
- end
614
-
615
- -- Display helpers
616
- function M.screenCenter()
617
- return display.contentCenterX, display.contentCenterY
618
- end
619
-
620
- function M.screenSize()
621
- return display.actualContentWidth, display.actualContentHeight
622
- end
623
-
624
- function M.isOffScreen(obj, margin)
625
- margin = margin or 50
626
- return obj.x < -margin or
627
- obj.x > display.actualContentWidth + margin or
628
- obj.y < -margin or
629
- obj.y > display.actualContentHeight + margin
630
- end
631
-
632
- return M
361
+
362
+ for i = 1, initialSize do
363
+ local obj = factory()
364
+ obj.isVisible = false
365
+ table.insert(state.pools[name].available, obj)
366
+ end
367
+ end
368
+
369
+ function M.getFromPool(name)
370
+ local pool = state.pools[name]
371
+ if not pool then return nil end
372
+
373
+ local obj = table.remove(pool.available)
374
+ if not obj then
375
+ obj = pool.factory()
376
+ end
377
+
378
+ obj.isVisible = true
379
+ table.insert(pool.inUse, obj)
380
+ return obj
381
+ end
382
+
383
+ function M.returnToPool(name, obj)
384
+ local pool = state.pools[name]
385
+ if not pool then return end
386
+
387
+ obj.isVisible = false
388
+ for i, inUseObj in ipairs(pool.inUse) do
389
+ if inUseObj == obj then
390
+ table.remove(pool.inUse, i)
391
+ break
392
+ end
393
+ end
394
+ table.insert(pool.available, obj)
395
+ end
396
+
397
+ -- Audio helpers
398
+ function M.playSound(filename, options)
399
+ options = options or {}
400
+ local sound = audio.loadSound("sounds/" .. filename)
401
+ local channel = audio.play(sound, {
402
+ channel = options.channel,
403
+ loops = options.loops or 0,
404
+ onComplete = options.onComplete,
405
+ })
406
+ return channel
407
+ end
408
+
409
+ function M.playMusic(filename, options)
410
+ options = options or {}
411
+ local music = audio.loadStream("music/" .. filename)
412
+ local channel = audio.play(music, {
413
+ channel = 1,
414
+ loops = options.loops or -1,
415
+ fadein = options.fadein or 0,
416
+ })
417
+ state.audioChannels.music = channel
418
+ return channel
419
+ end
420
+
421
+ function M.stopMusic(fadeout)
422
+ if state.audioChannels.music then
423
+ if fadeout and fadeout > 0 then
424
+ audio.fade({
425
+ channel = state.audioChannels.music,
426
+ time = fadeout,
427
+ volume = 0,
428
+ })
429
+ timer.performWithDelay(fadeout, function()
430
+ audio.stop(state.audioChannels.music)
431
+ end)
432
+ else
433
+ audio.stop(state.audioChannels.music)
434
+ end
435
+ end
436
+ end
437
+
438
+ -- Pause/Resume
439
+ function M.pause()
440
+ _G.GAME.state.isPaused = true
441
+ physics.pause()
442
+ Events.dispatch("game:pause", { isPaused = true })
443
+ end
444
+
445
+ function M.resume()
446
+ _G.GAME.state.isPaused = false
447
+ physics.start()
448
+ Events.dispatch("game:pause", { isPaused = false })
449
+ end
450
+
451
+ -- Cleanup
452
+ function M.cleanup()
453
+ -- Clear entities
454
+ for id, _ in pairs(state.entities) do
455
+ state.entities[id] = nil
456
+ end
457
+
458
+ -- Clear pools
459
+ for name, pool in pairs(state.pools) do
460
+ for _, obj in ipairs(pool.available) do
461
+ display.remove(obj)
462
+ end
463
+ for _, obj in ipairs(pool.inUse) do
464
+ display.remove(obj)
465
+ end
466
+ state.pools[name] = nil
467
+ end
468
+ end
469
+
470
+ return M
633
471
  `;
634
- this.addTextFile('modules/utils.lua', utilsLua);
635
- // Events
636
- const eventsLua = `-- Events Module
637
- -- Simple event system
638
- -- Generated from Nice2Dev
639
-
640
- local M = {}
641
-
642
- -- Private storage
643
- local listeners = {}
644
-
645
- -- Add event listener
646
- function M.on(eventName, callback)
647
- if not listeners[eventName] then
648
- listeners[eventName] = {}
649
- end
650
- table.insert(listeners[eventName], callback)
651
-
652
- -- Return unsubscribe function
653
- return function()
654
- M.off(eventName, callback)
655
- end
656
- end
657
-
658
- -- Remove event listener
659
- function M.off(eventName, callback)
660
- if listeners[eventName] then
661
- for i, cb in ipairs(listeners[eventName]) do
662
- if cb == callback then
663
- table.remove(listeners[eventName], i)
664
- break
665
- end
666
- end
667
- end
668
- end
669
-
670
- -- Dispatch event
671
- function M.dispatch(eventName, data)
672
- if listeners[eventName] then
673
- for _, callback in ipairs(listeners[eventName]) do
674
- local success, err = pcall(callback, data)
675
- if not success then
676
- print("[Events] Error in " .. eventName .. ": " .. tostring(err))
677
- end
678
- end
679
- end
680
- end
681
-
682
- -- Once (listen for single occurrence)
683
- function M.once(eventName, callback)
684
- local unsubscribe
685
- unsubscribe = M.on(eventName, function(data)
686
- unsubscribe()
687
- callback(data)
688
- end)
689
- return unsubscribe
690
- end
691
-
692
- -- Remove all listeners for an event
693
- function M.removeAll(eventName)
694
- listeners[eventName] = nil
695
- end
696
-
697
- -- Clear all listeners
698
- function M.clear()
699
- listeners = {}
700
- end
701
-
702
- return M
472
+ this.addTextFile("modules/game_manager.lua", gameManagerLua);
473
+ const utilsLua = `-- Utils Module
474
+ -- Common utility functions
475
+ -- Generated from Nice2Dev
476
+
477
+ local M = {}
478
+
479
+ -- Math utilities
480
+ function M.lerp(a, b, t)
481
+ return a + (b - a) * math.max(0, math.min(1, t))
482
+ end
483
+
484
+ function M.clamp(value, min, max)
485
+ return math.max(min, math.min(max, value))
486
+ end
487
+
488
+ function M.randomFloat(min, max)
489
+ return min + math.random() * (max - min)
490
+ end
491
+
492
+ function M.randomInt(min, max)
493
+ return math.random(min, max)
494
+ end
495
+
496
+ function M.distance(x1, y1, x2, y2)
497
+ local dx = x2 - x1
498
+ local dy = y2 - y1
499
+ return math.sqrt(dx * dx + dy * dy)
500
+ end
501
+
502
+ function M.angle(x1, y1, x2, y2)
503
+ return math.atan2(y2 - y1, x2 - x1)
504
+ end
505
+
506
+ function M.pointInRect(px, py, rx, ry, rw, rh)
507
+ return px >= rx and px <= rx + rw and py >= ry and py <= ry + rh
508
+ end
509
+
510
+ function M.rectsOverlap(r1x, r1y, r1w, r1h, r2x, r2y, r2w, r2h)
511
+ return r1x < r2x + r2w and
512
+ r1x + r1w > r2x and
513
+ r1y < r2y + r2h and
514
+ r1y + r1h > r2y
515
+ end
516
+
517
+ -- Table utilities
518
+ function M.tableContains(tbl, value)
519
+ for _, v in ipairs(tbl) do
520
+ if v == value then return true end
521
+ end
522
+ return false
523
+ end
524
+
525
+ function M.tableCopy(tbl)
526
+ local copy = {}
527
+ for k, v in pairs(tbl) do
528
+ if type(v) == "table" then
529
+ copy[k] = M.tableCopy(v)
530
+ else
531
+ copy[k] = v
532
+ end
533
+ end
534
+ return copy
535
+ end
536
+
537
+ function M.tableLength(tbl)
538
+ local count = 0
539
+ for _ in pairs(tbl) do count = count + 1 end
540
+ return count
541
+ end
542
+
543
+ function M.tableKeys(tbl)
544
+ local keys = {}
545
+ for k in pairs(tbl) do
546
+ table.insert(keys, k)
547
+ end
548
+ return keys
549
+ end
550
+
551
+ function M.shuffleTable(tbl)
552
+ for i = #tbl, 2, -1 do
553
+ local j = math.random(i)
554
+ tbl[i], tbl[j] = tbl[j], tbl[i]
555
+ end
556
+ return tbl
557
+ end
558
+
559
+ -- String utilities
560
+ function M.split(str, delimiter)
561
+ local result = {}
562
+ for match in (str .. delimiter):gmatch("(.-)" .. delimiter) do
563
+ table.insert(result, match)
564
+ end
565
+ return result
566
+ end
567
+
568
+ function M.trim(str)
569
+ return str:match("^%s*(.-)%s*$")
570
+ end
571
+
572
+ -- Timer helpers
573
+ function M.setTimeout(callback, delay)
574
+ return timer.performWithDelay(delay, callback)
575
+ end
576
+
577
+ function M.setInterval(callback, interval)
578
+ return timer.performWithDelay(interval, callback, 0)
579
+ end
580
+
581
+ function M.clearTimer(timerHandle)
582
+ if timerHandle then
583
+ timer.cancel(timerHandle)
584
+ end
585
+ end
586
+
587
+ -- Display helpers
588
+ function M.screenCenter()
589
+ return display.contentCenterX, display.contentCenterY
590
+ end
591
+
592
+ function M.screenSize()
593
+ return display.actualContentWidth, display.actualContentHeight
594
+ end
595
+
596
+ function M.isOffScreen(obj, margin)
597
+ margin = margin or 50
598
+ return obj.x < -margin or
599
+ obj.x > display.actualContentWidth + margin or
600
+ obj.y < -margin or
601
+ obj.y > display.actualContentHeight + margin
602
+ end
603
+
604
+ return M
703
605
  `;
704
- this.addTextFile('modules/events.lua', eventsLua);
705
- // Entity base class
706
- const entityLua = `-- Entity Module
707
- -- Base entity class for game objects
708
- -- Generated from Nice2Dev
709
-
710
- local M = {}
711
- M.__index = M
712
-
713
- local Utils = require("modules.utils")
714
- local Events = require("modules.events")
715
- local GameManager = require("modules.game_manager")
716
-
717
- -- Constructor
718
- function M.new(params)
719
- local self = setmetatable({}, M)
720
-
721
- params = params or {}
722
-
723
- self.id = params.id or tostring(os.time() .. math.random(1000, 9999))
724
- self.name = params.name or "Entity"
725
- self.tags = params.tags or {}
726
- self.isAlive = true
727
- self.components = {}
728
-
729
- -- Create display group
730
- self.group = display.newGroup()
731
- self.group.x = params.x or 0
732
- self.group.y = params.y or 0
733
- self.group.rotation = params.rotation or 0
734
- self.group.xScale = params.scaleX or 1
735
- self.group.yScale = params.scaleY or 1
736
-
737
- -- Reference back to entity
738
- self.group.entity = self
739
-
740
- -- Register with game manager
741
- GameManager.registerEntity(self)
742
-
743
- return self
744
- end
745
-
746
- -- Position getters/setters
747
- function M:getPosition()
748
- return self.group.x, self.group.y
749
- end
750
-
751
- function M:setPosition(x, y)
752
- self.group.x = x
753
- self.group.y = y
754
- end
755
-
756
- function M:move(dx, dy)
757
- self.group.x = self.group.x + dx
758
- self.group.y = self.group.y + dy
759
- end
760
-
761
- -- Rotation
762
- function M:getRotation()
763
- return self.group.rotation
764
- end
765
-
766
- function M:setRotation(angle)
767
- self.group.rotation = angle
768
- end
769
-
770
- function M:rotate(delta)
771
- self.group.rotation = self.group.rotation + delta
772
- end
773
-
774
- -- Scale
775
- function M:getScale()
776
- return self.group.xScale, self.group.yScale
777
- end
778
-
779
- function M:setScale(sx, sy)
780
- self.group.xScale = sx
781
- self.group.yScale = sy or sx
782
- end
783
-
784
- -- Tags
785
- function M:hasTag(tag)
786
- return Utils.tableContains(self.tags, tag)
787
- end
788
-
789
- function M:addTag(tag)
790
- if not self:hasTag(tag) then
791
- table.insert(self.tags, tag)
792
- end
793
- end
794
-
795
- function M:removeTag(tag)
796
- for i, t in ipairs(self.tags) do
797
- if t == tag then
798
- table.remove(self.tags, i)
799
- break
800
- end
801
- end
802
- end
803
-
804
- -- Components
805
- function M:addComponent(name, component)
806
- self.components[name] = component
807
- component.entity = self
808
- if component.init then
809
- component:init()
810
- end
811
- end
812
-
813
- function M:getComponent(name)
814
- return self.components[name]
815
- end
816
-
817
- function M:removeComponent(name)
818
- local component = self.components[name]
819
- if component then
820
- if component.destroy then
821
- component:destroy()
822
- end
823
- self.components[name] = nil
824
- end
825
- end
826
-
827
- -- Update (called each frame if registered)
828
- function M:update(dt)
829
- if not self.isAlive then return end
830
-
831
- -- Update all components
832
- for _, component in pairs(self.components) do
833
- if component.update then
834
- component:update(dt)
835
- end
836
- end
837
- end
838
-
839
- -- Destroy
840
- function M:destroy()
841
- if not self.isAlive then return end
842
-
843
- self.isAlive = false
844
-
845
- -- Destroy all components
846
- for name, component in pairs(self.components) do
847
- if component.destroy then
848
- component:destroy()
849
- end
850
- end
851
- self.components = {}
852
-
853
- -- Unregister
854
- GameManager.unregisterEntity(self.id)
855
-
856
- -- Remove display group
857
- if self.group then
858
- display.remove(self.group)
859
- self.group = nil
860
- end
861
-
862
- Events.dispatch("entity:destroyed", { id = self.id })
863
- end
864
-
865
- return M
606
+ this.addTextFile("modules/utils.lua", utilsLua);
607
+ const eventsLua = `-- Events Module
608
+ -- Simple event system
609
+ -- Generated from Nice2Dev
610
+
611
+ local M = {}
612
+
613
+ -- Private storage
614
+ local listeners = {}
615
+
616
+ -- Add event listener
617
+ function M.on(eventName, callback)
618
+ if not listeners[eventName] then
619
+ listeners[eventName] = {}
620
+ end
621
+ table.insert(listeners[eventName], callback)
622
+
623
+ -- Return unsubscribe function
624
+ return function()
625
+ M.off(eventName, callback)
626
+ end
627
+ end
628
+
629
+ -- Remove event listener
630
+ function M.off(eventName, callback)
631
+ if listeners[eventName] then
632
+ for i, cb in ipairs(listeners[eventName]) do
633
+ if cb == callback then
634
+ table.remove(listeners[eventName], i)
635
+ break
636
+ end
637
+ end
638
+ end
639
+ end
640
+
641
+ -- Dispatch event
642
+ function M.dispatch(eventName, data)
643
+ if listeners[eventName] then
644
+ for _, callback in ipairs(listeners[eventName]) do
645
+ local success, err = pcall(callback, data)
646
+ if not success then
647
+ print("[Events] Error in " .. eventName .. ": " .. tostring(err))
648
+ end
649
+ end
650
+ end
651
+ end
652
+
653
+ -- Once (listen for single occurrence)
654
+ function M.once(eventName, callback)
655
+ local unsubscribe
656
+ unsubscribe = M.on(eventName, function(data)
657
+ unsubscribe()
658
+ callback(data)
659
+ end)
660
+ return unsubscribe
661
+ end
662
+
663
+ -- Remove all listeners for an event
664
+ function M.removeAll(eventName)
665
+ listeners[eventName] = nil
666
+ end
667
+
668
+ -- Clear all listeners
669
+ function M.clear()
670
+ listeners = {}
671
+ end
672
+
673
+ return M
866
674
  `;
867
- this.addTextFile('modules/entity.lua', entityLua);
868
- }
869
- /* ── Scene Export ───────────────────────────────────────────── */
870
- async exportScene(scene, project, options) {
871
- const sceneName = scene.name.toLowerCase().replace(/[^a-z0-9_]/g, '_');
872
- options.platformOptions ?? {};
873
- const sceneLua = `-- Scene: ${scene.name}
874
- -- Generated from Nice2Dev
875
-
876
- local composer = require("composer")
877
- local physics = require("physics")
878
-
879
- local GameManager = require("modules.game_manager")
880
- local Events = require("modules.events")
881
- local Utils = require("modules.utils")
882
- local Entity = require("modules.entity")
883
-
884
- local scene = composer.newScene()
885
-
886
- ---------------------------------------------------------------------------------
887
- -- Scene Variables
888
- ---------------------------------------------------------------------------------
889
- local sceneGroup
890
- local entities = {}
891
- local timers = {}
892
- local listeners = {}
893
-
894
- ---------------------------------------------------------------------------------
895
- -- Scene Methods
896
- ---------------------------------------------------------------------------------
897
-
898
- -- Create scene objects
899
- function scene:create(event)
900
- sceneGroup = self.view
901
-
902
- -- Background
903
- local bg = display.newRect(sceneGroup, display.contentCenterX, display.contentCenterY,
904
- display.actualContentWidth, display.actualContentHeight)
905
- bg:setFillColor(${this.hexToRGB(scene.background ?? '#000000')})
906
-
907
- -- Create entities
908
- ${scene.entities.map((entity) => this.createEntityLua(entity)).join('\n')}
909
-
910
- print("[Scene] ${sceneName} created")
911
- end
912
-
913
- -- Show scene (transition in)
914
- function scene:show(event)
915
- sceneGroup = self.view
916
- local phase = event.phase
917
-
918
- if phase == "will" then
919
- -- Called when scene is about to appear
920
- elseif phase == "did" then
921
- -- Called when scene has fully appeared
922
-
923
- -- Start physics
924
- physics.start()
925
-
926
- -- Add update listener
927
- listeners.enterFrame = function(e)
928
- self:update(e)
929
- end
930
- Runtime:addEventListener("enterFrame", listeners.enterFrame)
931
-
932
- -- Add touch listener
933
- listeners.touch = function(e)
934
- return self:touch(e)
935
- end
936
- Runtime:addEventListener("touch", listeners.touch)
937
-
938
- _G.GAME.state.currentScene = "${sceneName}"
939
- Events.dispatch("scene:started", { name = "${sceneName}" })
940
-
941
- print("[Scene] ${sceneName} started")
942
- end
943
- end
944
-
945
- -- Hide scene (transition out)
946
- function scene:hide(event)
947
- sceneGroup = self.view
948
- local phase = event.phase
949
-
950
- if phase == "will" then
951
- -- Called when scene is about to hide
952
-
953
- -- Remove listeners
954
- if listeners.enterFrame then
955
- Runtime:removeEventListener("enterFrame", listeners.enterFrame)
956
- end
957
- if listeners.touch then
958
- Runtime:removeEventListener("touch", listeners.touch)
959
- end
960
-
961
- elseif phase == "did" then
962
- -- Called when scene has fully hidden
963
- physics.pause()
964
-
965
- Events.dispatch("scene:ended", { name = "${sceneName}" })
966
- print("[Scene] ${sceneName} hidden")
967
- end
968
- end
969
-
970
- -- Destroy scene
971
- function scene:destroy(event)
972
- sceneGroup = self.view
973
-
974
- -- Cancel timers
975
- for _, t in ipairs(timers) do
976
- timer.cancel(t)
977
- end
978
- timers = {}
979
-
980
- -- Destroy entities
981
- for _, entity in ipairs(entities) do
982
- if entity.destroy then
983
- entity:destroy()
984
- end
985
- end
986
- entities = {}
987
-
988
- print("[Scene] ${sceneName} destroyed")
989
- end
990
-
991
- ---------------------------------------------------------------------------------
992
- -- Update Loop
993
- ---------------------------------------------------------------------------------
994
- function scene:update(event)
995
- if _G.GAME.state.isPaused then return end
996
-
997
- local dt = event.time / 1000 -- Convert to seconds
998
-
999
- -- Update all entities
1000
- for i = #entities, 1, -1 do
1001
- local entity = entities[i]
1002
- if entity.isAlive then
1003
- if entity.update then
1004
- entity:update(dt)
1005
- end
1006
- else
1007
- table.remove(entities, i)
1008
- end
1009
- end
1010
- end
1011
-
1012
- ---------------------------------------------------------------------------------
1013
- -- Touch Handler
1014
- ---------------------------------------------------------------------------------
1015
- function scene:touch(event)
1016
- if event.phase == "began" then
1017
- -- Touch started
1018
- Events.dispatch("touch:start", { x = event.x, y = event.y })
1019
- elseif event.phase == "moved" then
1020
- -- Touch moved
1021
- Events.dispatch("touch:move", { x = event.x, y = event.y })
1022
- elseif event.phase == "ended" or event.phase == "cancelled" then
1023
- -- Touch ended
1024
- Events.dispatch("touch:end", { x = event.x, y = event.y })
1025
- end
1026
- return true
1027
- end
1028
-
1029
- ---------------------------------------------------------------------------------
1030
- -- Scene Event Listeners
1031
- ---------------------------------------------------------------------------------
1032
- scene:addEventListener("create", scene)
1033
- scene:addEventListener("show", scene)
1034
- scene:addEventListener("hide", scene)
1035
- scene:addEventListener("destroy", scene)
1036
-
1037
- return scene
675
+ this.addTextFile("modules/events.lua", eventsLua);
676
+ const entityLua = `-- Entity Module
677
+ -- Base entity class for game objects
678
+ -- Generated from Nice2Dev
679
+
680
+ local M = {}
681
+ M.__index = M
682
+
683
+ local Utils = require("modules.utils")
684
+ local Events = require("modules.events")
685
+ local GameManager = require("modules.game_manager")
686
+
687
+ -- Constructor
688
+ function M.new(params)
689
+ local self = setmetatable({}, M)
690
+
691
+ params = params or {}
692
+
693
+ self.id = params.id or tostring(os.time() .. math.random(1000, 9999))
694
+ self.name = params.name or "Entity"
695
+ self.tags = params.tags or {}
696
+ self.isAlive = true
697
+ self.components = {}
698
+
699
+ -- Create display group
700
+ self.group = display.newGroup()
701
+ self.group.x = params.x or 0
702
+ self.group.y = params.y or 0
703
+ self.group.rotation = params.rotation or 0
704
+ self.group.xScale = params.scaleX or 1
705
+ self.group.yScale = params.scaleY or 1
706
+
707
+ -- Reference back to entity
708
+ self.group.entity = self
709
+
710
+ -- Register with game manager
711
+ GameManager.registerEntity(self)
712
+
713
+ return self
714
+ end
715
+
716
+ -- Position getters/setters
717
+ function M:getPosition()
718
+ return self.group.x, self.group.y
719
+ end
720
+
721
+ function M:setPosition(x, y)
722
+ self.group.x = x
723
+ self.group.y = y
724
+ end
725
+
726
+ function M:move(dx, dy)
727
+ self.group.x = self.group.x + dx
728
+ self.group.y = self.group.y + dy
729
+ end
730
+
731
+ -- Rotation
732
+ function M:getRotation()
733
+ return self.group.rotation
734
+ end
735
+
736
+ function M:setRotation(angle)
737
+ self.group.rotation = angle
738
+ end
739
+
740
+ function M:rotate(delta)
741
+ self.group.rotation = self.group.rotation + delta
742
+ end
743
+
744
+ -- Scale
745
+ function M:getScale()
746
+ return self.group.xScale, self.group.yScale
747
+ end
748
+
749
+ function M:setScale(sx, sy)
750
+ self.group.xScale = sx
751
+ self.group.yScale = sy or sx
752
+ end
753
+
754
+ -- Tags
755
+ function M:hasTag(tag)
756
+ return Utils.tableContains(self.tags, tag)
757
+ end
758
+
759
+ function M:addTag(tag)
760
+ if not self:hasTag(tag) then
761
+ table.insert(self.tags, tag)
762
+ end
763
+ end
764
+
765
+ function M:removeTag(tag)
766
+ for i, t in ipairs(self.tags) do
767
+ if t == tag then
768
+ table.remove(self.tags, i)
769
+ break
770
+ end
771
+ end
772
+ end
773
+
774
+ -- Components
775
+ function M:addComponent(name, component)
776
+ self.components[name] = component
777
+ component.entity = self
778
+ if component.init then
779
+ component:init()
780
+ end
781
+ end
782
+
783
+ function M:getComponent(name)
784
+ return self.components[name]
785
+ end
786
+
787
+ function M:removeComponent(name)
788
+ local component = self.components[name]
789
+ if component then
790
+ if component.destroy then
791
+ component:destroy()
792
+ end
793
+ self.components[name] = nil
794
+ end
795
+ end
796
+
797
+ -- Update (called each frame if registered)
798
+ function M:update(dt)
799
+ if not self.isAlive then return end
800
+
801
+ -- Update all components
802
+ for _, component in pairs(self.components) do
803
+ if component.update then
804
+ component:update(dt)
805
+ end
806
+ end
807
+ end
808
+
809
+ -- Destroy
810
+ function M:destroy()
811
+ if not self.isAlive then return end
812
+
813
+ self.isAlive = false
814
+
815
+ -- Destroy all components
816
+ for name, component in pairs(self.components) do
817
+ if component.destroy then
818
+ component:destroy()
819
+ end
820
+ end
821
+ self.components = {}
822
+
823
+ -- Unregister
824
+ GameManager.unregisterEntity(self.id)
825
+
826
+ -- Remove display group
827
+ if self.group then
828
+ display.remove(self.group)
829
+ self.group = nil
830
+ end
831
+
832
+ Events.dispatch("entity:destroyed", { id = self.id })
833
+ end
834
+
835
+ return M
1038
836
  `;
1039
- this.addTextFile(`scenes/${sceneName}.lua`, sceneLua);
1040
- }
1041
- createEntityLua(entity) {
1042
- const name = (entity.name ?? entity.id).toLowerCase().replace(/[^a-z0-9_]/g, '_');
1043
- const pos = entity.position ?? { x: 0, y: 0 };
1044
- const scale = entity.scale ?? { x: 1, y: 1 };
1045
- const rotation = entity.rotation ?? 0;
1046
- const tags = entity.tags ?? [];
1047
- let entityLua = ` -- Entity: ${entity.name ?? entity.id}
1048
- local ${name} = Entity.new({
1049
- x = ${pos.x},
1050
- y = ${pos.y},
1051
- rotation = ${rotation},
1052
- scaleX = ${scale.x},
1053
- scaleY = ${scale.y},
1054
- name = "${entity.name ?? entity.id}",
1055
- tags = {${tags.map((t) => `"${t}"`).join(', ')}},
1056
- })
1057
- ${name}.group.anchorX = 0.5
1058
- ${name}.group.anchorY = 0.5
1059
- sceneGroup:insert(${name}.group)
1060
- table.insert(entities, ${name})
837
+ this.addTextFile("modules/entity.lua", entityLua);
838
+ }
839
+ /* ── Scene Export ───────────────────────────────────────────── */
840
+ async exportScene(scene, project, options) {
841
+ const sceneName = scene.name.toLowerCase().replace(/[^a-z0-9_]/g, "_");
842
+ options.platformOptions ?? {};
843
+ const sceneLua = `-- Scene: ${scene.name}
844
+ -- Generated from Nice2Dev
845
+
846
+ local composer = require("composer")
847
+ local physics = require("physics")
848
+
849
+ local GameManager = require("modules.game_manager")
850
+ local Events = require("modules.events")
851
+ local Utils = require("modules.utils")
852
+ local Entity = require("modules.entity")
853
+
854
+ local scene = composer.newScene()
855
+
856
+ ---------------------------------------------------------------------------------
857
+ -- Scene Variables
858
+ ---------------------------------------------------------------------------------
859
+ local sceneGroup
860
+ local entities = {}
861
+ local timers = {}
862
+ local listeners = {}
863
+
864
+ ---------------------------------------------------------------------------------
865
+ -- Scene Methods
866
+ ---------------------------------------------------------------------------------
867
+
868
+ -- Create scene objects
869
+ function scene:create(event)
870
+ sceneGroup = self.view
871
+
872
+ -- Background
873
+ local bg = display.newRect(sceneGroup, display.contentCenterX, display.contentCenterY,
874
+ display.actualContentWidth, display.actualContentHeight)
875
+ bg:setFillColor(${this.hexToRGB(scene.background ?? "#000000")})
876
+
877
+ -- Create entities
878
+ ${scene.entities.map((entity) => this.createEntityLua(entity)).join("\n")}
879
+
880
+ print("[Scene] ${sceneName} created")
881
+ end
882
+
883
+ -- Show scene (transition in)
884
+ function scene:show(event)
885
+ sceneGroup = self.view
886
+ local phase = event.phase
887
+
888
+ if phase == "will" then
889
+ -- Called when scene is about to appear
890
+ elseif phase == "did" then
891
+ -- Called when scene has fully appeared
892
+
893
+ -- Start physics
894
+ physics.start()
895
+
896
+ -- Add update listener
897
+ listeners.enterFrame = function(e)
898
+ self:update(e)
899
+ end
900
+ Runtime:addEventListener("enterFrame", listeners.enterFrame)
901
+
902
+ -- Add touch listener
903
+ listeners.touch = function(e)
904
+ return self:touch(e)
905
+ end
906
+ Runtime:addEventListener("touch", listeners.touch)
907
+
908
+ _G.GAME.state.currentScene = "${sceneName}"
909
+ Events.dispatch("scene:started", { name = "${sceneName}" })
910
+
911
+ print("[Scene] ${sceneName} started")
912
+ end
913
+ end
914
+
915
+ -- Hide scene (transition out)
916
+ function scene:hide(event)
917
+ sceneGroup = self.view
918
+ local phase = event.phase
919
+
920
+ if phase == "will" then
921
+ -- Called when scene is about to hide
922
+
923
+ -- Remove listeners
924
+ if listeners.enterFrame then
925
+ Runtime:removeEventListener("enterFrame", listeners.enterFrame)
926
+ end
927
+ if listeners.touch then
928
+ Runtime:removeEventListener("touch", listeners.touch)
929
+ end
930
+
931
+ elseif phase == "did" then
932
+ -- Called when scene has fully hidden
933
+ physics.pause()
934
+
935
+ Events.dispatch("scene:ended", { name = "${sceneName}" })
936
+ print("[Scene] ${sceneName} hidden")
937
+ end
938
+ end
939
+
940
+ -- Destroy scene
941
+ function scene:destroy(event)
942
+ sceneGroup = self.view
943
+
944
+ -- Cancel timers
945
+ for _, t in ipairs(timers) do
946
+ timer.cancel(t)
947
+ end
948
+ timers = {}
949
+
950
+ -- Destroy entities
951
+ for _, entity in ipairs(entities) do
952
+ if entity.destroy then
953
+ entity:destroy()
954
+ end
955
+ end
956
+ entities = {}
957
+
958
+ print("[Scene] ${sceneName} destroyed")
959
+ end
960
+
961
+ ---------------------------------------------------------------------------------
962
+ -- Update Loop
963
+ ---------------------------------------------------------------------------------
964
+ function scene:update(event)
965
+ if _G.GAME.state.isPaused then return end
966
+
967
+ local dt = event.time / 1000 -- Convert to seconds
968
+
969
+ -- Update all entities
970
+ for i = #entities, 1, -1 do
971
+ local entity = entities[i]
972
+ if entity.isAlive then
973
+ if entity.update then
974
+ entity:update(dt)
975
+ end
976
+ else
977
+ table.remove(entities, i)
978
+ end
979
+ end
980
+ end
981
+
982
+ ---------------------------------------------------------------------------------
983
+ -- Touch Handler
984
+ ---------------------------------------------------------------------------------
985
+ function scene:touch(event)
986
+ if event.phase == "began" then
987
+ -- Touch started
988
+ Events.dispatch("touch:start", { x = event.x, y = event.y })
989
+ elseif event.phase == "moved" then
990
+ -- Touch moved
991
+ Events.dispatch("touch:move", { x = event.x, y = event.y })
992
+ elseif event.phase == "ended" or event.phase == "cancelled" then
993
+ -- Touch ended
994
+ Events.dispatch("touch:end", { x = event.x, y = event.y })
995
+ end
996
+ return true
997
+ end
998
+
999
+ ---------------------------------------------------------------------------------
1000
+ -- Scene Event Listeners
1001
+ ---------------------------------------------------------------------------------
1002
+ scene:addEventListener("create", scene)
1003
+ scene:addEventListener("show", scene)
1004
+ scene:addEventListener("hide", scene)
1005
+ scene:addEventListener("destroy", scene)
1006
+
1007
+ return scene
1061
1008
  `;
1062
- // Add sprite if present
1063
- const spriteComp = entity.components.find((c) => c.type === 'sprite');
1064
- if (spriteComp) {
1065
- const texture = spriteComp.properties?.['texture'] ?? 'placeholder.png';
1066
- entityLua += ` local ${name}_sprite = display.newImageRect(${name}.group, "images/${texture}", ${32 * scale.x}, ${32 * scale.y})
1067
- ${name}_sprite.x = 0
1068
- ${name}_sprite.y = 0
1009
+ this.addTextFile(`scenes/${sceneName}.lua`, sceneLua);
1010
+ }
1011
+ createEntityLua(entity) {
1012
+ const name = (entity.name ?? entity.id).toLowerCase().replace(/[^a-z0-9_]/g, "_");
1013
+ const pos = entity.position ?? { x: 0, y: 0 };
1014
+ const scale = entity.scale ?? { x: 1, y: 1 };
1015
+ const rotation = entity.rotation ?? 0;
1016
+ const tags = entity.tags ?? [];
1017
+ let entityLua = ` -- Entity: ${entity.name ?? entity.id}
1018
+ local ${name} = Entity.new({
1019
+ x = ${pos.x},
1020
+ y = ${pos.y},
1021
+ rotation = ${rotation},
1022
+ scaleX = ${scale.x},
1023
+ scaleY = ${scale.y},
1024
+ name = "${entity.name ?? entity.id}",
1025
+ tags = {${tags.map((t) => `"${t}"`).join(", ")}},
1026
+ })
1027
+ ${name}.group.anchorX = 0.5
1028
+ ${name}.group.anchorY = 0.5
1029
+ sceneGroup:insert(${name}.group)
1030
+ table.insert(entities, ${name})
1069
1031
  `;
1070
- }
1071
- // Add physics if rigidbody
1072
- const rigidbodyComp = entity.components.find((c) => c.type === 'rigidbody');
1073
- if (rigidbodyComp) {
1074
- const bodyType = rigidbodyComp.properties?.['isKinematic']
1075
- ? 'kinematic'
1076
- : 'dynamic';
1077
- const mass = rigidbodyComp.properties?.['mass'] ?? 1;
1078
- entityLua += ` physics.addBody(${name}.group, "${bodyType}", {
1079
- density = ${mass},
1080
- friction = 0.5,
1081
- bounce = 0.2,
1082
- })
1032
+ const spriteComp = entity.components.find((c) => c.type === "sprite");
1033
+ if (spriteComp) {
1034
+ const texture = spriteComp.properties?.["texture"] ?? "placeholder.png";
1035
+ entityLua += ` local ${name}_sprite = display.newImageRect(${name}.group, "images/${texture}", ${32 * scale.x}, ${32 * scale.y})
1036
+ ${name}_sprite.x = 0
1037
+ ${name}_sprite.y = 0
1083
1038
  `;
1084
- }
1085
- return entityLua;
1086
- }
1087
- hexToRGB(hex) {
1088
- const cleanHex = hex.replace('#', '');
1089
- const r = parseInt(cleanHex.substring(0, 2), 16) / 255;
1090
- const g = parseInt(cleanHex.substring(2, 4), 16) / 255;
1091
- const b = parseInt(cleanHex.substring(4, 6), 16) / 255;
1092
- return `${r.toFixed(2)}, ${g.toFixed(2)}, ${b.toFixed(2)}`;
1093
1039
  }
1094
- /* ── Prefab Export ──────────────────────────────────────────── */
1095
- async exportPrefab(prefab, _options) {
1096
- const prefabName = prefab.name.toLowerCase().replace(/[^a-z0-9_]/g, '_');
1097
- const entity = prefab.entity;
1098
- const tags = entity.tags ?? [];
1099
- const prefabLua = `-- Prefab: ${prefab.name}
1100
- -- Generated from Nice2Dev
1101
-
1102
- local Entity = require("modules.entity")
1103
-
1104
- local M = {}
1105
-
1106
- function M.create(params)
1107
- params = params or {}
1108
-
1109
- local entity = Entity.new({
1110
- id = params.id,
1111
- name = "${prefab.name}",
1112
- x = params.x or 0,
1113
- y = params.y or 0,
1114
- rotation = params.rotation or ${entity.rotation ?? 0},
1115
- scaleX = params.scaleX or ${entity.scale?.x ?? 1},
1116
- scaleY = params.scaleY or ${entity.scale?.y ?? 1},
1117
- tags = params.tags or {${tags.map((t) => `"${t}"`).join(', ')}},
1118
- })
1119
-
1120
- ${entity.components.map((c) => this.componentToLua(c, prefabName)).join('\n')}
1121
-
1122
- return entity
1123
- end
1124
-
1125
- return M
1040
+ const rigidbodyComp = entity.components.find((c) => c.type === "rigidbody");
1041
+ if (rigidbodyComp) {
1042
+ const bodyType = rigidbodyComp.properties?.["isKinematic"] ? "kinematic" : "dynamic";
1043
+ const mass = rigidbodyComp.properties?.["mass"] ?? 1;
1044
+ entityLua += ` physics.addBody(${name}.group, "${bodyType}", {
1045
+ density = ${mass},
1046
+ friction = 0.5,
1047
+ bounce = 0.2,
1048
+ })
1126
1049
  `;
1127
- this.addTextFile(`prefabs/${prefabName}.lua`, prefabLua);
1128
1050
  }
1129
- componentToLua(component, _entityName) {
1130
- switch (component.type) {
1131
- case 'sprite': {
1132
- const texture = component.properties?.['texture'] ?? 'placeholder.png';
1133
- return ` -- Sprite component
1134
- local sprite = display.newImageRect(entity.group, "images/${texture}", 32, 32)
1135
- sprite.x = 0
1051
+ return entityLua;
1052
+ }
1053
+ hexToRGB(hex) {
1054
+ const cleanHex = hex.replace("#", "");
1055
+ const r = parseInt(cleanHex.substring(0, 2), 16) / 255;
1056
+ const g = parseInt(cleanHex.substring(2, 4), 16) / 255;
1057
+ const b = parseInt(cleanHex.substring(4, 6), 16) / 255;
1058
+ return `${r.toFixed(2)}, ${g.toFixed(2)}, ${b.toFixed(2)}`;
1059
+ }
1060
+ /* ── Prefab Export ──────────────────────────────────────────── */
1061
+ async exportPrefab(prefab, _options) {
1062
+ const prefabName = prefab.name.toLowerCase().replace(/[^a-z0-9_]/g, "_");
1063
+ const entity = prefab.entity;
1064
+ const tags = entity.tags ?? [];
1065
+ const prefabLua = `-- Prefab: ${prefab.name}
1066
+ -- Generated from Nice2Dev
1067
+
1068
+ local Entity = require("modules.entity")
1069
+
1070
+ local M = {}
1071
+
1072
+ function M.create(params)
1073
+ params = params or {}
1074
+
1075
+ local entity = Entity.new({
1076
+ id = params.id,
1077
+ name = "${prefab.name}",
1078
+ x = params.x or 0,
1079
+ y = params.y or 0,
1080
+ rotation = params.rotation or ${entity.rotation ?? 0},
1081
+ scaleX = params.scaleX or ${entity.scale?.x ?? 1},
1082
+ scaleY = params.scaleY or ${entity.scale?.y ?? 1},
1083
+ tags = params.tags or {${tags.map((t) => `"${t}"`).join(", ")}},
1084
+ })
1085
+
1086
+ ${entity.components.map((c) => this.componentToLua(c, prefabName)).join("\n")}
1087
+
1088
+ return entity
1089
+ end
1090
+
1091
+ return M
1092
+ `;
1093
+ this.addTextFile(`prefabs/${prefabName}.lua`, prefabLua);
1094
+ }
1095
+ componentToLua(component, _entityName) {
1096
+ switch (component.type) {
1097
+ case "sprite": {
1098
+ const texture = component.properties?.["texture"] ?? "placeholder.png";
1099
+ return ` -- Sprite component
1100
+ local sprite = display.newImageRect(entity.group, "images/${texture}", 32, 32)
1101
+ sprite.x = 0
1136
1102
  sprite.y = 0`;
1137
- }
1138
- case 'rigidbody': {
1139
- const bodyType = component.properties?.['isKinematic']
1140
- ? 'kinematic'
1141
- : 'dynamic';
1142
- const mass = component.properties?.['mass'] ?? 1;
1143
- return ` -- Physics component
1144
- local physics = require("physics")
1145
- physics.addBody(entity.group, "${bodyType}", {
1146
- density = ${mass},
1147
- friction = 0.5,
1148
- bounce = 0.2,
1103
+ }
1104
+ case "rigidbody": {
1105
+ const bodyType = component.properties?.["isKinematic"] ? "kinematic" : "dynamic";
1106
+ const mass = component.properties?.["mass"] ?? 1;
1107
+ return ` -- Physics component
1108
+ local physics = require("physics")
1109
+ physics.addBody(entity.group, "${bodyType}", {
1110
+ density = ${mass},
1111
+ friction = 0.5,
1112
+ bounce = 0.2,
1149
1113
  })`;
1150
- }
1151
- default:
1152
- return ` -- ${component.type} component (custom)`;
1153
- }
1114
+ }
1115
+ default:
1116
+ return ` -- ${component.type} component (custom)`;
1154
1117
  }
1155
- /* ── README ─────────────────────────────────────────────────── */
1156
- async generateReadme(project, _options) {
1157
- const readme = `# ${project.name} - Solar2D Export
1158
-
1159
- Generated from Nice2Dev project v${project.version}
1160
-
1161
- ## Requirements
1162
-
1163
- - Solar2D Simulator (download from https://solar2d.com/)
1164
- - Solar2D account for building
1165
-
1166
- ## Installation
1167
-
1168
- 1. Open Solar2D Simulator
1169
- 2. File > Open Project
1170
- 3. Select this folder
1171
- 4. Click "Open main.lua"
1172
-
1173
- ## Project Structure
1174
-
1175
- - \`main.lua\` - Entry point
1176
- - \`config.lua\` - App configuration
1177
- - \`build.settings\` - Build settings for all platforms
1178
- - \`modules/\` - Core modules
1179
- - \`game_manager.lua\` - Central game state
1180
- - \`utils.lua\` - Utility functions
1181
- - \`events.lua\` - Event system
1182
- - \`entity.lua\` - Entity base class
1183
- - \`scenes/\` - Composer scenes
1184
- - \`prefabs/\` - Spawnable prefabs
1185
- - \`images/\` - Image assets (add your own)
1186
- - \`sounds/\` - Sound effects (add your own)
1187
- - \`music/\` - Background music (add your own)
1188
-
1189
- ## Scenes
1190
-
1191
- ${project.scenes.map((s) => `- ${s.name} (${s.entities.length} entities)`).join('\n')}
1192
-
1193
- ## Building
1194
-
1195
- ### Simulator
1196
- Just open main.lua in Solar2D Simulator.
1197
-
1198
- ### Device Build
1199
- 1. File > Build
1200
- 2. Select platform (iOS, Android, HTML5, etc.)
1201
- 3. Configure signing (for iOS/Android)
1202
- 4. Build!
1203
-
1204
- ### HTML5
1205
- 1. File > Build > HTML5
1206
- 2. Upload build folder to web server
1207
-
1208
- ## Key Modules
1209
-
1210
- ### GameManager
1211
- \`\`\`lua
1212
- local GameManager = require("modules.game_manager")
1213
-
1214
- -- Register entity
1215
- GameManager.registerEntity(entity)
1216
-
1217
- -- Get entities by tag
1218
- local enemies = GameManager.getEntitiesByTag("enemy")
1219
-
1220
- -- Play sound
1221
- GameManager.playSound("explosion.wav")
1222
-
1223
- -- Play music
1224
- GameManager.playMusic("background.mp3", { loops = -1 })
1225
- \`\`\`
1226
-
1227
- ### Events
1228
- \`\`\`lua
1229
- local Events = require("modules.events")
1230
-
1231
- -- Listen for event
1232
- Events.on("game:pause", function(data)
1233
- print("Game paused:", data.isPaused)
1234
- end)
1235
-
1236
- -- Dispatch event
1237
- Events.dispatch("game:pause", { isPaused = true })
1238
- \`\`\`
1239
-
1240
- ### Entity
1241
- \`\`\`lua
1242
- local Entity = require("modules.entity")
1243
-
1244
- local player = Entity.new({
1245
- x = 100,
1246
- y = 200,
1247
- name = "Player",
1248
- tags = {"player"},
1249
- })
1250
-
1251
- player:setPosition(300, 400)
1252
- player:rotate(45)
1253
- player:destroy()
1254
- \`\`\`
1255
-
1256
- ## Notes
1257
-
1258
- - Add your image assets to \`images/\` folder
1259
- - Add sound effects to \`sounds/\` folder
1260
- - Add music to \`music/\` folder
1261
- - Physics uses Box2D (built-in)
1262
- - Scenes use Composer for lifecycle management
1263
-
1264
- ## Settings
1265
-
1266
- - Resolution: ${project.settings.resolution.width}x${project.settings.resolution.height}
1267
- - Physics: ${project.settings.physics.enabled ? 'Enabled' : 'Disabled'}
1268
- - Gravity: (${project.settings.physics.gravity.x}, ${project.settings.physics.gravity.y})
1269
- - Master Volume: ${project.settings.audio.masterVolume}
1118
+ }
1119
+ /* ── README ─────────────────────────────────────────────────── */
1120
+ async generateReadme(project, _options) {
1121
+ const readme = `# ${project.name} - Solar2D Export
1122
+
1123
+ Generated from Nice2Dev project v${project.version}
1124
+
1125
+ ## Requirements
1126
+
1127
+ - Solar2D Simulator (download from https://solar2d.com/)
1128
+ - Solar2D account for building
1129
+
1130
+ ## Installation
1131
+
1132
+ 1. Open Solar2D Simulator
1133
+ 2. File > Open Project
1134
+ 3. Select this folder
1135
+ 4. Click "Open main.lua"
1136
+
1137
+ ## Project Structure
1138
+
1139
+ - \`main.lua\` - Entry point
1140
+ - \`config.lua\` - App configuration
1141
+ - \`build.settings\` - Build settings for all platforms
1142
+ - \`modules/\` - Core modules
1143
+ - \`game_manager.lua\` - Central game state
1144
+ - \`utils.lua\` - Utility functions
1145
+ - \`events.lua\` - Event system
1146
+ - \`entity.lua\` - Entity base class
1147
+ - \`scenes/\` - Composer scenes
1148
+ - \`prefabs/\` - Spawnable prefabs
1149
+ - \`images/\` - Image assets (add your own)
1150
+ - \`sounds/\` - Sound effects (add your own)
1151
+ - \`music/\` - Background music (add your own)
1152
+
1153
+ ## Scenes
1154
+
1155
+ ${project.scenes.map((s) => `- ${s.name} (${s.entities.length} entities)`).join("\n")}
1156
+
1157
+ ## Building
1158
+
1159
+ ### Simulator
1160
+ Just open main.lua in Solar2D Simulator.
1161
+
1162
+ ### Device Build
1163
+ 1. File > Build
1164
+ 2. Select platform (iOS, Android, HTML5, etc.)
1165
+ 3. Configure signing (for iOS/Android)
1166
+ 4. Build!
1167
+
1168
+ ### HTML5
1169
+ 1. File > Build > HTML5
1170
+ 2. Upload build folder to web server
1171
+
1172
+ ## Key Modules
1173
+
1174
+ ### GameManager
1175
+ \`\`\`lua
1176
+ local GameManager = require("modules.game_manager")
1177
+
1178
+ -- Register entity
1179
+ GameManager.registerEntity(entity)
1180
+
1181
+ -- Get entities by tag
1182
+ local enemies = GameManager.getEntitiesByTag("enemy")
1183
+
1184
+ -- Play sound
1185
+ GameManager.playSound("explosion.wav")
1186
+
1187
+ -- Play music
1188
+ GameManager.playMusic("background.mp3", { loops = -1 })
1189
+ \`\`\`
1190
+
1191
+ ### Events
1192
+ \`\`\`lua
1193
+ local Events = require("modules.events")
1194
+
1195
+ -- Listen for event
1196
+ Events.on("game:pause", function(data)
1197
+ print("Game paused:", data.isPaused)
1198
+ end)
1199
+
1200
+ -- Dispatch event
1201
+ Events.dispatch("game:pause", { isPaused = true })
1202
+ \`\`\`
1203
+
1204
+ ### Entity
1205
+ \`\`\`lua
1206
+ local Entity = require("modules.entity")
1207
+
1208
+ local player = Entity.new({
1209
+ x = 100,
1210
+ y = 200,
1211
+ name = "Player",
1212
+ tags = {"player"},
1213
+ })
1214
+
1215
+ player:setPosition(300, 400)
1216
+ player:rotate(45)
1217
+ player:destroy()
1218
+ \`\`\`
1219
+
1220
+ ## Notes
1221
+
1222
+ - Add your image assets to \`images/\` folder
1223
+ - Add sound effects to \`sounds/\` folder
1224
+ - Add music to \`music/\` folder
1225
+ - Physics uses Box2D (built-in)
1226
+ - Scenes use Composer for lifecycle management
1227
+
1228
+ ## Settings
1229
+
1230
+ - Resolution: ${project.settings.resolution.width}x${project.settings.resolution.height}
1231
+ - Physics: ${project.settings.physics.enabled ? "Enabled" : "Disabled"}
1232
+ - Gravity: (${project.settings.physics.gravity.x}, ${project.settings.physics.gravity.y})
1233
+ - Master Volume: ${project.settings.audio.masterVolume}
1270
1234
  `;
1271
- this.addTextFile('README.md', readme);
1272
- }
1235
+ this.addTextFile("README.md", readme);
1236
+ }
1273
1237
  }
1274
- /* ── Factory ──────────────────────────────────────────────────── */
1275
1238
  function createSolar2DExporter() {
1276
- return new Solar2DExporter();
1239
+ return new Solar2DExporter();
1277
1240
  }
1278
-
1279
- export { Solar2DExporter, createSolar2DExporter };
1241
+ export {
1242
+ Solar2DExporter,
1243
+ createSolar2DExporter
1244
+ };