@nice2dev/game-engine 1.3.15 → 1.3.17

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,1314 +1,1257 @@
1
- 'use strict';
2
-
3
- var PlatformExporter = require('./PlatformExporter.js');
4
-
5
- /* ────────────────────────────────────────────────────────────────
6
- TIC-80 Exporter — Fantasy Computer Export
7
-
8
- Exports Nice2Dev projects to TIC-80 format:
9
- - TIC cartridge file format (.tic)
10
- - Support for Lua, JavaScript, and Moonscript
11
- - Sprites, map, sound, music
12
-
13
- Specs:
14
- - 240x136 pixels
15
- - 16 colors palette
16
- - 256 8x8 sprites
17
- - Free and open source
18
- ──────────────────────────────────────────────────────────────── */
19
- /* ── TIC-80 Constants ─────────────────────────────────────────── */
1
+ "use strict";
2
+ Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
3
+ const PlatformExporter = require("./PlatformExporter.js");
20
4
  const TIC80_PALETTE = [
21
- '#1a1c2c', // 0 - dark purple
22
- '#5d275d', // 1 - magenta
23
- '#b13e53', // 2 - red
24
- '#ef7d57', // 3 - orange
25
- '#ffcd75', // 4 - yellow
26
- '#a7f070', // 5 - lime
27
- '#38b764', // 6 - green
28
- '#257179', // 7 - teal
29
- '#29366f', // 8 - dark blue
30
- '#3b5dc9', // 9 - blue
31
- '#41a6f6', // 10 - sky blue
32
- '#73eff7', // 11 - cyan
33
- '#f4f4f4', // 12 - white
34
- '#94b0c2', // 13 - light gray
35
- '#566c86', // 14 - gray
36
- '#333c57', // 15 - dark gray
5
+ "#1a1c2c",
6
+ // 0 - dark purple
7
+ "#5d275d",
8
+ // 1 - magenta
9
+ "#b13e53",
10
+ // 2 - red
11
+ "#ef7d57",
12
+ // 3 - orange
13
+ "#ffcd75",
14
+ // 4 - yellow
15
+ "#a7f070",
16
+ // 5 - lime
17
+ "#38b764",
18
+ // 6 - green
19
+ "#257179",
20
+ // 7 - teal
21
+ "#29366f",
22
+ // 8 - dark blue
23
+ "#3b5dc9",
24
+ // 9 - blue
25
+ "#41a6f6",
26
+ // 10 - sky blue
27
+ "#73eff7",
28
+ // 11 - cyan
29
+ "#f4f4f4",
30
+ // 12 - white
31
+ "#94b0c2",
32
+ // 13 - light gray
33
+ "#566c86",
34
+ // 14 - gray
35
+ "#333c57"
36
+ // 15 - dark gray
37
37
  ];
38
38
  const TIC80_WIDTH = 240;
39
39
  const TIC80_HEIGHT = 136;
40
- /* ── Exporter Implementation ──────────────────────────────────── */
41
40
  class Tic80Exporter extends PlatformExporter.PlatformExporter {
42
- constructor() {
43
- super(...arguments);
44
- this.platformId = 'tic80';
45
- this.platformInfo = {
46
- id: 'tic80',
47
- name: 'TIC-80',
48
- description: 'TIC-80 tiny computer - Free and open-source fantasy console',
49
- website: 'https://tic80.com/',
50
- features: ['2d-rendering', 'pixel-graphics', 'audio', 'music', 'retro', 'multi-language'],
51
- supportedAssets: ['sprite', 'tilemap', 'audio', 'music'],
52
- exportFormats: ['.tic', '.lua', '.js', '.moon'],
53
- };
41
+ constructor() {
42
+ super(...arguments);
43
+ this.platformId = "tic80";
44
+ this.platformInfo = {
45
+ id: "tic80",
46
+ name: "TIC-80",
47
+ description: "TIC-80 tiny computer - Free and open-source fantasy console",
48
+ website: "https://tic80.com/",
49
+ features: ["2d-rendering", "pixel-graphics", "audio", "music", "retro", "multi-language"],
50
+ supportedAssets: ["sprite", "tilemap", "audio", "music"],
51
+ exportFormats: [".tic", ".lua", ".js", ".moon"]
52
+ };
53
+ }
54
+ async doExport(project, options) {
55
+ const platformOpts = options.platformOptions ?? {};
56
+ const language = platformOpts.language ?? "lua";
57
+ let code;
58
+ let extension;
59
+ switch (language) {
60
+ case "javascript":
61
+ code = this.generateJavaScriptCode(project, options);
62
+ extension = "js";
63
+ break;
64
+ case "moonscript":
65
+ code = this.generateMoonscriptCode(project, options);
66
+ extension = "moon";
67
+ break;
68
+ case "wren":
69
+ code = this.generateWrenCode(project, options);
70
+ extension = "wren";
71
+ break;
72
+ case "lua":
73
+ default:
74
+ code = this.generateLuaCode(project, options);
75
+ extension = "lua";
76
+ break;
54
77
  }
55
- async doExport(project, options) {
56
- const platformOpts = options.platformOptions ?? {};
57
- const language = platformOpts.language ?? 'lua';
58
- // Generate code based on language
59
- let code;
60
- let extension;
61
- switch (language) {
62
- case 'javascript':
63
- code = this.generateJavaScriptCode(project, options);
64
- extension = 'js';
65
- break;
66
- case 'moonscript':
67
- code = this.generateMoonscriptCode(project, options);
68
- extension = 'moon';
69
- break;
70
- case 'wren':
71
- code = this.generateWrenCode(project, options);
72
- extension = 'wren';
73
- break;
74
- case 'lua':
75
- default:
76
- code = this.generateLuaCode(project, options);
77
- extension = 'lua';
78
- break;
79
- }
80
- // Generate TIC file (text format - can be loaded in TIC-80)
81
- await this.generateTicFile(project, code, language, options);
82
- // Generate standalone source file
83
- const safeName = (options.projectName ?? project.name)
84
- .toLowerCase()
85
- .replace(/[^a-z0-9_]/g, '_');
86
- this.addTextFile(`${safeName}.${extension}`, code);
87
- // Generate README
88
- await this.generateReadme(project, options);
89
- }
90
- /* ── TIC File Generation ────────────────────────────────────── */
91
- async generateTicFile(project, code, language, options) {
92
- const safeName = (options.projectName ?? project.name)
93
- .toLowerCase()
94
- .replace(/[^a-z0-9_]/g, '_');
95
- const platformOpts = options.platformOptions ?? {};
96
- // TIC-80 uses a specific text format for .tic files
97
- let ticContent = '';
98
- // Metadata
99
- ticContent += `-- title: ${project.name}\n`;
100
- ticContent += `-- author: Nice2Dev Export\n`;
101
- ticContent += `-- desc: Generated from Nice2Dev v${project.version}\n`;
102
- ticContent += `-- site: https://nice2dev.com\n`;
103
- ticContent += `-- license: MIT\n`;
104
- ticContent += `-- version: ${project.version}\n`;
105
- ticContent += `-- script: ${language}\n`;
106
- ticContent += '\n';
107
- // Code section
108
- ticContent += code;
109
- ticContent += '\n';
110
- // Sprites section (placeholder)
111
- ticContent += this.generateSpritesSection(project);
112
- ticContent += '\n';
113
- // Map section
114
- ticContent += this.generateMapSection(project);
115
- ticContent += '\n';
116
- // Waves section (sound waveforms)
117
- ticContent += this.generateWavesSection(project, options);
118
- ticContent += '\n';
119
- // SFX section
120
- if (platformOpts.sfxPlaceholders) {
121
- ticContent += this.generateSfxSection(project);
122
- ticContent += '\n';
123
- }
124
- // Music patterns
125
- if (platformOpts.musicPatterns) {
126
- ticContent += this.generateMusicSection(project);
127
- ticContent += '\n';
128
- }
129
- // Palette section
130
- ticContent += this.generatePaletteSection();
131
- this.addTextFile(`${safeName}.tic`, ticContent);
78
+ await this.generateTicFile(project, code, language, options);
79
+ const safeName = (options.projectName ?? project.name).toLowerCase().replace(/[^a-z0-9_]/g, "_");
80
+ this.addTextFile(`${safeName}.${extension}`, code);
81
+ await this.generateReadme(project, options);
82
+ }
83
+ /* ── TIC File Generation ────────────────────────────────────── */
84
+ async generateTicFile(project, code, language, options) {
85
+ const safeName = (options.projectName ?? project.name).toLowerCase().replace(/[^a-z0-9_]/g, "_");
86
+ const platformOpts = options.platformOptions ?? {};
87
+ let ticContent = "";
88
+ ticContent += `-- title: ${project.name}
89
+ `;
90
+ ticContent += `-- author: Nice2Dev Export
91
+ `;
92
+ ticContent += `-- desc: Generated from Nice2Dev v${project.version}
93
+ `;
94
+ ticContent += `-- site: https://nice2dev.com
95
+ `;
96
+ ticContent += `-- license: MIT
97
+ `;
98
+ ticContent += `-- version: ${project.version}
99
+ `;
100
+ ticContent += `-- script: ${language}
101
+ `;
102
+ ticContent += "\n";
103
+ ticContent += code;
104
+ ticContent += "\n";
105
+ ticContent += this.generateSpritesSection(project);
106
+ ticContent += "\n";
107
+ ticContent += this.generateMapSection(project);
108
+ ticContent += "\n";
109
+ ticContent += this.generateWavesSection(project, options);
110
+ ticContent += "\n";
111
+ if (platformOpts.sfxPlaceholders) {
112
+ ticContent += this.generateSfxSection(project);
113
+ ticContent += "\n";
132
114
  }
133
- /* ── Lua Code Generation ────────────────────────────────────── */
134
- generateLuaCode(project, options) {
135
- const platformOpts = options.platformOptions ?? {};
136
- const lines = [];
137
- // Game state
138
- lines.push('-- Game State');
139
- lines.push('local game = {');
140
- lines.push(' t = 0,');
141
- lines.push(' state = "play",');
142
- lines.push(' cam = {x = 0, y = 0},');
143
- lines.push(' entities = {},');
144
- lines.push(` debug = ${platformOpts.includeDebug ?? false}`);
145
- lines.push('}');
146
- lines.push('');
147
- // Constants
148
- lines.push('-- Constants');
149
- lines.push(`local SCREEN_W = ${TIC80_WIDTH}`);
150
- lines.push(`local SCREEN_H = ${TIC80_HEIGHT}`);
151
- lines.push('');
152
- // Core functions
153
- lines.push(this.generateLuaCoreFunctions(project, options));
154
- // Entity system
155
- lines.push(this.generateLuaEntitySystem());
156
- // Entity definitions
157
- lines.push(this.generateLuaEntityDefinitions(project));
158
- // Scene management
159
- lines.push(this.generateLuaSceneManagement(project));
160
- // Utilities
161
- lines.push(this.generateLuaUtilities(platformOpts.includeDebug ?? false));
162
- return lines.join('\n');
115
+ if (platformOpts.musicPatterns) {
116
+ ticContent += this.generateMusicSection(project);
117
+ ticContent += "\n";
163
118
  }
164
- generateLuaCoreFunctions(project, _options) {
165
- const bgColor = this.getClosestTic80Color(project.scenes[0]?.background ?? '#1a1c2c');
166
- return `
167
- -- Boot (called once)
168
- function BOOT()
169
- -- Initialize
170
- trace("${project.name} v${project.version}")
171
- load_scene(1)
172
- end
173
-
174
- -- TIC (main loop, 60fps)
175
- function TIC()
176
- game.t = game.t + 1
177
-
178
- if game.state == "play" then
179
- -- Update
180
- update_entities()
181
- check_collisions()
182
- cleanup_dead()
183
-
184
- -- Draw
185
- cls(${bgColor})
186
- draw_map()
187
- draw_entities()
188
- draw_ui()
189
-
190
- if game.debug then
191
- draw_debug()
192
- end
193
- end
194
- end
195
-
196
- -- Called when scanline is drawn (for effects)
197
- function scanline(row)
198
- -- Scanline effects here
199
- end
200
-
201
- -- Called before each line is drawn
202
- function BDR(row)
203
- -- Border effects
204
- end
205
-
206
- -- Override palette (called on startup)
207
- function OVR()
208
- -- Overlay/palette effects
209
- end
210
-
211
- -- Boot message
212
- function MENU(index)
213
- if index == 0 then
214
- trace("Restart")
215
- BOOT()
216
- end
217
- end
119
+ ticContent += this.generatePaletteSection();
120
+ this.addTextFile(`${safeName}.tic`, ticContent);
121
+ }
122
+ /* ── Lua Code Generation ────────────────────────────────────── */
123
+ generateLuaCode(project, options) {
124
+ const platformOpts = options.platformOptions ?? {};
125
+ const lines = [];
126
+ lines.push("-- Game State");
127
+ lines.push("local game = {");
128
+ lines.push(" t = 0,");
129
+ lines.push(' state = "play",');
130
+ lines.push(" cam = {x = 0, y = 0},");
131
+ lines.push(" entities = {},");
132
+ lines.push(` debug = ${platformOpts.includeDebug ?? false}`);
133
+ lines.push("}");
134
+ lines.push("");
135
+ lines.push("-- Constants");
136
+ lines.push(`local SCREEN_W = ${TIC80_WIDTH}`);
137
+ lines.push(`local SCREEN_H = ${TIC80_HEIGHT}`);
138
+ lines.push("");
139
+ lines.push(this.generateLuaCoreFunctions(project, options));
140
+ lines.push(this.generateLuaEntitySystem());
141
+ lines.push(this.generateLuaEntityDefinitions(project));
142
+ lines.push(this.generateLuaSceneManagement(project));
143
+ lines.push(this.generateLuaUtilities(platformOpts.includeDebug ?? false));
144
+ return lines.join("\n");
145
+ }
146
+ generateLuaCoreFunctions(project, _options) {
147
+ const bgColor = this.getClosestTic80Color(project.scenes[0]?.background ?? "#1a1c2c");
148
+ return `
149
+ -- Boot (called once)
150
+ function BOOT()
151
+ -- Initialize
152
+ trace("${project.name} v${project.version}")
153
+ load_scene(1)
154
+ end
155
+
156
+ -- TIC (main loop, 60fps)
157
+ function TIC()
158
+ game.t = game.t + 1
159
+
160
+ if game.state == "play" then
161
+ -- Update
162
+ update_entities()
163
+ check_collisions()
164
+ cleanup_dead()
165
+
166
+ -- Draw
167
+ cls(${bgColor})
168
+ draw_map()
169
+ draw_entities()
170
+ draw_ui()
171
+
172
+ if game.debug then
173
+ draw_debug()
174
+ end
175
+ end
176
+ end
177
+
178
+ -- Called when scanline is drawn (for effects)
179
+ function scanline(row)
180
+ -- Scanline effects here
181
+ end
182
+
183
+ -- Called before each line is drawn
184
+ function BDR(row)
185
+ -- Border effects
186
+ end
187
+
188
+ -- Override palette (called on startup)
189
+ function OVR()
190
+ -- Overlay/palette effects
191
+ end
192
+
193
+ -- Boot message
194
+ function MENU(index)
195
+ if index == 0 then
196
+ trace("Restart")
197
+ BOOT()
198
+ end
199
+ end
218
200
  `;
219
- }
220
- generateLuaEntitySystem() {
221
- return `
222
- -- Entity System
223
- local entity_mt = {}
224
- entity_mt.__index = entity_mt
225
-
226
- function make_entity(type_name, x, y, props)
227
- local e = setmetatable({
228
- type = type_name,
229
- x = x or 0,
230
- y = y or 0,
231
- dx = 0,
232
- dy = 0,
233
- w = 8,
234
- h = 8,
235
- spr = 0,
236
- flip = 0,
237
- scale = 1,
238
- anim = {frames = {0}, speed = 0.1, t = 0, i = 1},
239
- dead = false,
240
- solid = false,
241
- tags = {},
242
- }, entity_mt)
243
-
244
- -- Apply custom properties
245
- if props then
246
- for k, v in pairs(props) do
247
- e[k] = v
248
- end
249
- end
250
-
251
- -- Apply type defaults
252
- if entity_types[type_name] then
253
- local def = entity_types[type_name]
254
- for k, v in pairs(def) do
255
- if type(v) ~= "function" then
256
- e[k] = v
257
- end
258
- end
259
- if def.init then
260
- def.init(e)
261
- end
262
- end
263
-
264
- table.insert(game.entities, e)
265
- return e
266
- end
267
-
268
- function entity_mt:update()
269
- -- Movement
270
- self.x = self.x + self.dx
271
- self.y = self.y + self.dy
272
-
273
- -- Friction
274
- self.dx = self.dx * 0.9
275
- self.dy = self.dy * 0.9
276
-
277
- -- Animation
278
- if self.anim.speed > 0 then
279
- self.anim.t = self.anim.t + self.anim.speed
280
- if self.anim.t >= 1 then
281
- self.anim.t = 0
282
- self.anim.i = self.anim.i + 1
283
- if self.anim.i > #self.anim.frames then
284
- self.anim.i = 1
285
- end
286
- self.spr = self.anim.frames[self.anim.i]
287
- end
288
- end
289
- end
290
-
291
- function entity_mt:draw()
292
- spr(self.spr, self.x - game.cam.x, self.y - game.cam.y, 0, self.scale, self.flip)
293
- end
294
-
295
- function entity_mt:has_tag(tag)
296
- for _, t in ipairs(self.tags) do
297
- if t == tag then return true end
298
- end
299
- return false
300
- end
301
-
302
- function entity_mt:kill()
303
- self.dead = true
304
- end
305
-
306
- function update_entities()
307
- for _, e in ipairs(game.entities) do
308
- if not e.dead then
309
- -- Call type-specific update
310
- if entity_types[e.type] and entity_types[e.type].update then
311
- entity_types[e.type].update(e)
312
- else
313
- e:update()
314
- end
315
- end
316
- end
317
- end
318
-
319
- function draw_entities()
320
- -- Sort by Y for proper layering
321
- table.sort(game.entities, function(a, b) return a.y < b.y end)
322
-
323
- for _, e in ipairs(game.entities) do
324
- if not e.dead then
325
- -- Call type-specific draw
326
- if entity_types[e.type] and entity_types[e.type].draw then
327
- entity_types[e.type].draw(e)
328
- else
329
- e:draw()
330
- end
331
- end
332
- end
333
- end
334
-
335
- function cleanup_dead()
336
- for i = #game.entities, 1, -1 do
337
- if game.entities[i].dead then
338
- table.remove(game.entities, i)
339
- end
340
- end
341
- end
342
-
343
- function check_collisions()
344
- for i = 1, #game.entities do
345
- local a = game.entities[i]
346
- if not a.dead and a.solid then
347
- for j = i + 1, #game.entities do
348
- local b = game.entities[j]
349
- if not b.dead and b.solid then
350
- if collides(a, b) then
351
- if entity_types[a.type] and entity_types[a.type].on_collision then
352
- entity_types[a.type].on_collision(a, b)
353
- end
354
- if entity_types[b.type] and entity_types[b.type].on_collision then
355
- entity_types[b.type].on_collision(b, a)
356
- end
357
- end
358
- end
359
- end
360
- end
361
- end
362
- end
363
-
364
- function collides(a, b)
365
- return a.x < b.x + b.w and
366
- a.x + a.w > b.x and
367
- a.y < b.y + b.h and
368
- a.y + a.h > b.y
369
- end
201
+ }
202
+ generateLuaEntitySystem() {
203
+ return `
204
+ -- Entity System
205
+ local entity_mt = {}
206
+ entity_mt.__index = entity_mt
207
+
208
+ function make_entity(type_name, x, y, props)
209
+ local e = setmetatable({
210
+ type = type_name,
211
+ x = x or 0,
212
+ y = y or 0,
213
+ dx = 0,
214
+ dy = 0,
215
+ w = 8,
216
+ h = 8,
217
+ spr = 0,
218
+ flip = 0,
219
+ scale = 1,
220
+ anim = {frames = {0}, speed = 0.1, t = 0, i = 1},
221
+ dead = false,
222
+ solid = false,
223
+ tags = {},
224
+ }, entity_mt)
225
+
226
+ -- Apply custom properties
227
+ if props then
228
+ for k, v in pairs(props) do
229
+ e[k] = v
230
+ end
231
+ end
232
+
233
+ -- Apply type defaults
234
+ if entity_types[type_name] then
235
+ local def = entity_types[type_name]
236
+ for k, v in pairs(def) do
237
+ if type(v) ~= "function" then
238
+ e[k] = v
239
+ end
240
+ end
241
+ if def.init then
242
+ def.init(e)
243
+ end
244
+ end
245
+
246
+ table.insert(game.entities, e)
247
+ return e
248
+ end
249
+
250
+ function entity_mt:update()
251
+ -- Movement
252
+ self.x = self.x + self.dx
253
+ self.y = self.y + self.dy
254
+
255
+ -- Friction
256
+ self.dx = self.dx * 0.9
257
+ self.dy = self.dy * 0.9
258
+
259
+ -- Animation
260
+ if self.anim.speed > 0 then
261
+ self.anim.t = self.anim.t + self.anim.speed
262
+ if self.anim.t >= 1 then
263
+ self.anim.t = 0
264
+ self.anim.i = self.anim.i + 1
265
+ if self.anim.i > #self.anim.frames then
266
+ self.anim.i = 1
267
+ end
268
+ self.spr = self.anim.frames[self.anim.i]
269
+ end
270
+ end
271
+ end
272
+
273
+ function entity_mt:draw()
274
+ spr(self.spr, self.x - game.cam.x, self.y - game.cam.y, 0, self.scale, self.flip)
275
+ end
276
+
277
+ function entity_mt:has_tag(tag)
278
+ for _, t in ipairs(self.tags) do
279
+ if t == tag then return true end
280
+ end
281
+ return false
282
+ end
283
+
284
+ function entity_mt:kill()
285
+ self.dead = true
286
+ end
287
+
288
+ function update_entities()
289
+ for _, e in ipairs(game.entities) do
290
+ if not e.dead then
291
+ -- Call type-specific update
292
+ if entity_types[e.type] and entity_types[e.type].update then
293
+ entity_types[e.type].update(e)
294
+ else
295
+ e:update()
296
+ end
297
+ end
298
+ end
299
+ end
300
+
301
+ function draw_entities()
302
+ -- Sort by Y for proper layering
303
+ table.sort(game.entities, function(a, b) return a.y < b.y end)
304
+
305
+ for _, e in ipairs(game.entities) do
306
+ if not e.dead then
307
+ -- Call type-specific draw
308
+ if entity_types[e.type] and entity_types[e.type].draw then
309
+ entity_types[e.type].draw(e)
310
+ else
311
+ e:draw()
312
+ end
313
+ end
314
+ end
315
+ end
316
+
317
+ function cleanup_dead()
318
+ for i = #game.entities, 1, -1 do
319
+ if game.entities[i].dead then
320
+ table.remove(game.entities, i)
321
+ end
322
+ end
323
+ end
324
+
325
+ function check_collisions()
326
+ for i = 1, #game.entities do
327
+ local a = game.entities[i]
328
+ if not a.dead and a.solid then
329
+ for j = i + 1, #game.entities do
330
+ local b = game.entities[j]
331
+ if not b.dead and b.solid then
332
+ if collides(a, b) then
333
+ if entity_types[a.type] and entity_types[a.type].on_collision then
334
+ entity_types[a.type].on_collision(a, b)
335
+ end
336
+ if entity_types[b.type] and entity_types[b.type].on_collision then
337
+ entity_types[b.type].on_collision(b, a)
338
+ end
339
+ end
340
+ end
341
+ end
342
+ end
343
+ end
344
+ end
345
+
346
+ function collides(a, b)
347
+ return a.x < b.x + b.w and
348
+ a.x + a.w > b.x and
349
+ a.y < b.y + b.h and
350
+ a.y + a.h > b.y
351
+ end
370
352
  `;
353
+ }
354
+ generateLuaEntityDefinitions(project) {
355
+ const lines = [];
356
+ lines.push("");
357
+ lines.push("-- Entity Type Definitions");
358
+ lines.push("entity_types = {}");
359
+ lines.push("");
360
+ const entityTypes = /* @__PURE__ */ new Map();
361
+ for (const prefab of project.prefabs) {
362
+ entityTypes.set(prefab.name.toLowerCase().replace(/[^a-z0-9_]/g, "_"), prefab.entity);
371
363
  }
372
- generateLuaEntityDefinitions(project) {
373
- const lines = [];
374
- lines.push('');
375
- lines.push('-- Entity Type Definitions');
376
- lines.push('entity_types = {}');
377
- lines.push('');
378
- // Gather all entity types
379
- const entityTypes = new Map();
380
- for (const prefab of project.prefabs) {
381
- entityTypes.set(prefab.name.toLowerCase().replace(/[^a-z0-9_]/g, '_'), prefab.entity);
382
- }
383
- for (const scene of project.scenes) {
384
- for (const entity of scene.entities) {
385
- const typeName = (entity.name ?? entity.id).toLowerCase().replace(/[^a-z0-9_]/g, '_');
386
- if (!entityTypes.has(typeName)) {
387
- entityTypes.set(typeName, entity);
388
- }
389
- }
364
+ for (const scene of project.scenes) {
365
+ for (const entity of scene.entities) {
366
+ const typeName = (entity.name ?? entity.id).toLowerCase().replace(/[^a-z0-9_]/g, "_");
367
+ if (!entityTypes.has(typeName)) {
368
+ entityTypes.set(typeName, entity);
390
369
  }
391
- for (const [typeName, entity] of entityTypes) {
392
- lines.push(this.entityTypeToLuaDef(typeName, entity));
393
- }
394
- return lines.join('\n');
370
+ }
371
+ }
372
+ for (const [typeName, entity] of entityTypes) {
373
+ lines.push(this.entityTypeToLuaDef(typeName, entity));
395
374
  }
396
- entityTypeToLuaDef(typeName, entity) {
397
- const tags = entity.tags ?? [];
398
- const hasPhysics = entity.components.some((c) => c.type === 'rigidbody');
399
- const sprIndex = this.getEntitySpriteIndex(entity);
400
- const speed = this.getComponentProperty(entity, 'movement', 'speed', 50) / 50;
401
- return `entity_types["${typeName}"] = {
402
- spr = ${sprIndex},
403
- w = 8,
404
- h = 8,
405
- solid = ${hasPhysics},
406
- tags = {${tags.map((t) => `"${t}"`).join(', ')}},
407
- speed = ${speed},
408
- hp = ${this.getComponentProperty(entity, 'health', 'max', 3)},
409
-
410
- init = function(self)
411
- -- Custom initialization
412
- end,
413
-
414
- update = function(self)
415
- -- Custom update logic
416
- self:update()
417
- end,
418
-
419
- draw = function(self)
420
- self:draw()
421
- end,
422
-
423
- on_collision = function(self, other)
424
- -- Collision handling
425
- end,
426
- }
427
-
375
+ return lines.join("\n");
376
+ }
377
+ entityTypeToLuaDef(typeName, entity) {
378
+ const tags = entity.tags ?? [];
379
+ const hasPhysics = entity.components.some((c) => c.type === "rigidbody");
380
+ const sprIndex = this.getEntitySpriteIndex(entity);
381
+ const speed = this.getComponentProperty(entity, "movement", "speed", 50) / 50;
382
+ return `entity_types["${typeName}"] = {
383
+ spr = ${sprIndex},
384
+ w = 8,
385
+ h = 8,
386
+ solid = ${hasPhysics},
387
+ tags = {${tags.map((t) => `"${t}"`).join(", ")}},
388
+ speed = ${speed},
389
+ hp = ${this.getComponentProperty(entity, "health", "max", 3)},
390
+
391
+ init = function(self)
392
+ -- Custom initialization
393
+ end,
394
+
395
+ update = function(self)
396
+ -- Custom update logic
397
+ self:update()
398
+ end,
399
+
400
+ draw = function(self)
401
+ self:draw()
402
+ end,
403
+
404
+ on_collision = function(self, other)
405
+ -- Collision handling
406
+ end,
407
+ }
408
+
428
409
  `;
410
+ }
411
+ getEntitySpriteIndex(entity) {
412
+ const name = (entity.name ?? "entity").toLowerCase();
413
+ if (name.includes("player")) {
414
+ return 1;
429
415
  }
430
- getEntitySpriteIndex(entity) {
431
- const name = (entity.name ?? 'entity').toLowerCase();
432
- if (name.includes('player')) {
433
- return 1;
434
- }
435
- if (name.includes('enemy')) {
436
- return 17;
437
- }
438
- if (name.includes('item')) {
439
- return 33;
440
- }
441
- if (name.includes('bullet')) {
442
- return 49;
443
- }
444
- return 0;
416
+ if (name.includes("enemy")) {
417
+ return 17;
445
418
  }
446
- getComponentProperty(entity, componentType, property, defaultValue) {
447
- const comp = entity.components.find((c) => c.type === componentType);
448
- if (comp && comp.properties && property in comp.properties) {
449
- return comp.properties[property];
450
- }
451
- return defaultValue;
419
+ if (name.includes("item")) {
420
+ return 33;
452
421
  }
453
- generateLuaSceneManagement(project) {
454
- const lines = [];
455
- lines.push('');
456
- lines.push('-- Scenes');
457
- lines.push('local scenes = {}');
458
- lines.push('');
459
- for (let i = 0; i < project.scenes.length; i++) {
460
- const scene = project.scenes[i];
461
- const sceneName = scene.name.toLowerCase().replace(/[^a-z0-9_]/g, '_');
462
- lines.push(`scenes[${i + 1}] = {`);
463
- lines.push(` name = "${sceneName}",`);
464
- lines.push(` entities = {`);
465
- for (const entity of scene.entities) {
466
- const typeName = (entity.name ?? entity.id).toLowerCase().replace(/[^a-z0-9_]/g, '_');
467
- const pos = entity.position ?? { x: 0, y: 0 };
468
- // Scale position for TIC-80 (240x136)
469
- const x = Math.floor((pos.x / project.settings.resolution.width) * TIC80_WIDTH);
470
- const y = Math.floor((pos.y / project.settings.resolution.height) * TIC80_HEIGHT);
471
- lines.push(` {type = "${typeName}", x = ${x}, y = ${y}},`);
472
- }
473
- lines.push(` }`);
474
- lines.push(`}`);
475
- lines.push('');
476
- }
477
- lines.push(`function load_scene(index)
478
- game.entities = {}
479
- local scene = scenes[index]
480
- if scene then
481
- for _, e in ipairs(scene.entities) do
482
- make_entity(e.type, e.x, e.y)
483
- end
484
- trace("Loaded scene: " .. scene.name)
485
- end
486
- end
487
- `);
488
- return lines.join('\n');
422
+ if (name.includes("bullet")) {
423
+ return 49;
424
+ }
425
+ return 0;
426
+ }
427
+ getComponentProperty(entity, componentType, property, defaultValue) {
428
+ const comp = entity.components.find((c) => c.type === componentType);
429
+ if (comp && comp.properties && property in comp.properties) {
430
+ return comp.properties[property];
431
+ }
432
+ return defaultValue;
433
+ }
434
+ generateLuaSceneManagement(project) {
435
+ const lines = [];
436
+ lines.push("");
437
+ lines.push("-- Scenes");
438
+ lines.push("local scenes = {}");
439
+ lines.push("");
440
+ for (let i = 0; i < project.scenes.length; i++) {
441
+ const scene = project.scenes[i];
442
+ const sceneName = scene.name.toLowerCase().replace(/[^a-z0-9_]/g, "_");
443
+ lines.push(`scenes[${i + 1}] = {`);
444
+ lines.push(` name = "${sceneName}",`);
445
+ lines.push(` entities = {`);
446
+ for (const entity of scene.entities) {
447
+ const typeName = (entity.name ?? entity.id).toLowerCase().replace(/[^a-z0-9_]/g, "_");
448
+ const pos = entity.position ?? { x: 0, y: 0 };
449
+ const x = Math.floor(pos.x / project.settings.resolution.width * TIC80_WIDTH);
450
+ const y = Math.floor(pos.y / project.settings.resolution.height * TIC80_HEIGHT);
451
+ lines.push(` {type = "${typeName}", x = ${x}, y = ${y}},`);
452
+ }
453
+ lines.push(` }`);
454
+ lines.push(`}`);
455
+ lines.push("");
489
456
  }
490
- generateLuaUtilities(includeDebug) {
491
- let code = `
492
- -- Utilities
493
- function lerp(a, b, t)
494
- return a + (b - a) * math.max(0, math.min(1, t))
495
- end
496
-
497
- function dist(x1, y1, x2, y2)
498
- local dx = x2 - x1
499
- local dy = y2 - y1
500
- return math.sqrt(dx * dx + dy * dy)
501
- end
502
-
503
- function clamp(v, min, max)
504
- return math.max(min, math.min(max, v))
505
- end
506
-
507
- function sign(v)
508
- return v > 0 and 1 or v < 0 and -1 or 0
509
- end
510
-
511
- function draw_map()
512
- map(0, 0, 30, 17, 0, 0, 0)
513
- end
514
-
515
- function draw_ui()
516
- -- HUD
517
- print("Nice2Dev", 2, 2, 12)
518
- end
519
-
520
- function spawn_particle(x, y, color)
521
- make_entity("particle", x, y, {
522
- spr = -1,
523
- dx = math.random() * 2 - 1,
524
- dy = math.random() * 2 - 1,
525
- c = color,
526
- life = 15 + math.random(10),
527
- draw = function(self)
528
- pix(self.x, self.y, self.c)
529
- end,
530
- update = function(self)
531
- self.x = self.x + self.dx
532
- self.y = self.y + self.dy
533
- self.dy = self.dy + 0.1
534
- self.life = self.life - 1
535
- if self.life <= 0 then
536
- self.dead = true
537
- end
538
- end,
539
- })
540
- end
541
-
542
- -- Particle pseudo-type
543
- entity_types["particle"] = {
544
- spr = -1,
545
- solid = false,
546
- }
457
+ lines.push(`function load_scene(index)
458
+ game.entities = {}
459
+ local scene = scenes[index]
460
+ if scene then
461
+ for _, e in ipairs(scene.entities) do
462
+ make_entity(e.type, e.x, e.y)
463
+ end
464
+ trace("Loaded scene: " .. scene.name)
465
+ end
466
+ end
467
+ `);
468
+ return lines.join("\n");
469
+ }
470
+ generateLuaUtilities(includeDebug) {
471
+ let code = `
472
+ -- Utilities
473
+ function lerp(a, b, t)
474
+ return a + (b - a) * math.max(0, math.min(1, t))
475
+ end
476
+
477
+ function dist(x1, y1, x2, y2)
478
+ local dx = x2 - x1
479
+ local dy = y2 - y1
480
+ return math.sqrt(dx * dx + dy * dy)
481
+ end
482
+
483
+ function clamp(v, min, max)
484
+ return math.max(min, math.min(max, v))
485
+ end
486
+
487
+ function sign(v)
488
+ return v > 0 and 1 or v < 0 and -1 or 0
489
+ end
490
+
491
+ function draw_map()
492
+ map(0, 0, 30, 17, 0, 0, 0)
493
+ end
494
+
495
+ function draw_ui()
496
+ -- HUD
497
+ print("Nice2Dev", 2, 2, 12)
498
+ end
499
+
500
+ function spawn_particle(x, y, color)
501
+ make_entity("particle", x, y, {
502
+ spr = -1,
503
+ dx = math.random() * 2 - 1,
504
+ dy = math.random() * 2 - 1,
505
+ c = color,
506
+ life = 15 + math.random(10),
507
+ draw = function(self)
508
+ pix(self.x, self.y, self.c)
509
+ end,
510
+ update = function(self)
511
+ self.x = self.x + self.dx
512
+ self.y = self.y + self.dy
513
+ self.dy = self.dy + 0.1
514
+ self.life = self.life - 1
515
+ if self.life <= 0 then
516
+ self.dead = true
517
+ end
518
+ end,
519
+ })
520
+ end
521
+
522
+ -- Particle pseudo-type
523
+ entity_types["particle"] = {
524
+ spr = -1,
525
+ solid = false,
526
+ }
547
527
  `;
548
- if (includeDebug) {
549
- code += `
550
- function draw_debug()
551
- local mem = pmem(0) or 0
552
- local fps = 60
553
-
554
- rect(0, 0, 80, 16, 0)
555
- print("fps:" .. fps, 2, 2, 12)
556
- print("ent:" .. #game.entities, 2, 9, 12)
557
-
558
- -- Draw hitboxes
559
- for _, e in ipairs(game.entities) do
560
- if e.solid then
561
- rectb(e.x - game.cam.x, e.y - game.cam.y, e.w, e.h, 2)
562
- end
563
- end
564
- end
528
+ if (includeDebug) {
529
+ code += `
530
+ function draw_debug()
531
+ local mem = pmem(0) or 0
532
+ local fps = 60
533
+
534
+ rect(0, 0, 80, 16, 0)
535
+ print("fps:" .. fps, 2, 2, 12)
536
+ print("ent:" .. #game.entities, 2, 9, 12)
537
+
538
+ -- Draw hitboxes
539
+ for _, e in ipairs(game.entities) do
540
+ if e.solid then
541
+ rectb(e.x - game.cam.x, e.y - game.cam.y, e.w, e.h, 2)
542
+ end
543
+ end
544
+ end
565
545
  `;
566
- }
567
- else {
568
- code += `
569
- function draw_debug()
570
- -- Debug disabled
571
- end
546
+ } else {
547
+ code += `
548
+ function draw_debug()
549
+ -- Debug disabled
550
+ end
572
551
  `;
552
+ }
553
+ return code;
554
+ }
555
+ /* ── JavaScript Code Generation ─────────────────────────────── */
556
+ generateJavaScriptCode(project, options) {
557
+ const lines = [];
558
+ lines.push(`// ${project.name} - TIC-80 JavaScript`);
559
+ lines.push("// Generated from Nice2Dev");
560
+ lines.push("");
561
+ lines.push("// Game State");
562
+ lines.push("var game = {");
563
+ lines.push(" t: 0,");
564
+ lines.push(' state: "play",');
565
+ lines.push(" cam: {x: 0, y: 0},");
566
+ lines.push(" entities: [],");
567
+ lines.push(` debug: ${options.platformOptions?.includeDebug ?? false}`);
568
+ lines.push("};");
569
+ lines.push("");
570
+ lines.push(`
571
+ // Boot
572
+ function BOOT() {
573
+ trace("${project.name} v${project.version}");
574
+ loadScene(1);
575
+ }
576
+
577
+ // Main loop
578
+ function TIC() {
579
+ game.t++;
580
+
581
+ if (game.state === "play") {
582
+ updateEntities();
583
+ checkCollisions();
584
+ cleanupDead();
585
+
586
+ cls(0);
587
+ drawMap();
588
+ drawEntities();
589
+ drawUI();
590
+
591
+ if (game.debug) {
592
+ drawDebug();
593
+ }
594
+ }
595
+ }
596
+
597
+ // Entity functions
598
+ function makeEntity(typeName, x, y, props) {
599
+ var e = {
600
+ type: typeName,
601
+ x: x || 0,
602
+ y: y || 0,
603
+ dx: 0,
604
+ dy: 0,
605
+ w: 8,
606
+ h: 8,
607
+ spr: 0,
608
+ flip: 0,
609
+ dead: false,
610
+ solid: false,
611
+ tags: []
612
+ };
613
+
614
+ // Apply type defaults
615
+ var def = entityTypes[typeName];
616
+ if (def) {
617
+ for (var k in def) {
618
+ if (typeof def[k] !== 'function') {
619
+ e[k] = def[k];
620
+ }
621
+ }
622
+ if (def.init) def.init(e);
623
+ }
624
+
625
+ // Apply custom props
626
+ if (props) {
627
+ for (var k in props) {
628
+ e[k] = props[k];
629
+ }
630
+ }
631
+
632
+ game.entities.push(e);
633
+ return e;
634
+ }
635
+
636
+ function updateEntities() {
637
+ game.entities.forEach(function(e) {
638
+ if (!e.dead) {
639
+ var def = entityTypes[e.type];
640
+ if (def && def.update) {
641
+ def.update(e);
642
+ } else {
643
+ // Default update
644
+ e.x += e.dx;
645
+ e.y += e.dy;
646
+ e.dx *= 0.9;
647
+ e.dy *= 0.9;
648
+ }
649
+ }
650
+ });
651
+ }
652
+
653
+ function drawEntities() {
654
+ // Sort by Y
655
+ game.entities.sort(function(a, b) { return a.y - b.y; });
656
+
657
+ game.entities.forEach(function(e) {
658
+ if (!e.dead) {
659
+ var def = entityTypes[e.type];
660
+ if (def && def.draw) {
661
+ def.draw(e);
662
+ } else {
663
+ spr(e.spr, e.x - game.cam.x, e.y - game.cam.y, 0, 1, e.flip);
664
+ }
665
+ }
666
+ });
667
+ }
668
+
669
+ function cleanupDead() {
670
+ game.entities = game.entities.filter(function(e) { return !e.dead; });
671
+ }
672
+
673
+ function checkCollisions() {
674
+ for (var i = 0; i < game.entities.length; i++) {
675
+ var a = game.entities[i];
676
+ if (!a.dead && a.solid) {
677
+ for (var j = i + 1; j < game.entities.length; j++) {
678
+ var b = game.entities[j];
679
+ if (!b.dead && b.solid && collides(a, b)) {
680
+ var defA = entityTypes[a.type];
681
+ var defB = entityTypes[b.type];
682
+ if (defA && defA.onCollision) defA.onCollision(a, b);
683
+ if (defB && defB.onCollision) defB.onCollision(b, a);
573
684
  }
574
- return code;
685
+ }
575
686
  }
576
- /* ── JavaScript Code Generation ─────────────────────────────── */
577
- generateJavaScriptCode(project, options) {
578
- const lines = [];
579
- lines.push(`// ${project.name} - TIC-80 JavaScript`);
580
- lines.push('// Generated from Nice2Dev');
581
- lines.push('');
582
- // Game state
583
- lines.push('// Game State');
584
- lines.push('var game = {');
585
- lines.push(' t: 0,');
586
- lines.push(' state: "play",');
587
- lines.push(' cam: {x: 0, y: 0},');
588
- lines.push(' entities: [],');
589
- lines.push(` debug: ${options.platformOptions?.includeDebug ?? false}`);
590
- lines.push('};');
591
- lines.push('');
592
- // Core functions
593
- lines.push(`
594
- // Boot
595
- function BOOT() {
596
- trace("${project.name} v${project.version}");
597
- loadScene(1);
598
- }
599
-
600
- // Main loop
601
- function TIC() {
602
- game.t++;
603
-
604
- if (game.state === "play") {
605
- updateEntities();
606
- checkCollisions();
607
- cleanupDead();
608
-
609
- cls(0);
610
- drawMap();
611
- drawEntities();
612
- drawUI();
613
-
614
- if (game.debug) {
615
- drawDebug();
616
- }
617
- }
618
- }
619
-
620
- // Entity functions
621
- function makeEntity(typeName, x, y, props) {
622
- var e = {
623
- type: typeName,
624
- x: x || 0,
625
- y: y || 0,
626
- dx: 0,
627
- dy: 0,
628
- w: 8,
629
- h: 8,
630
- spr: 0,
631
- flip: 0,
632
- dead: false,
633
- solid: false,
634
- tags: []
635
- };
636
-
637
- // Apply type defaults
638
- var def = entityTypes[typeName];
639
- if (def) {
640
- for (var k in def) {
641
- if (typeof def[k] !== 'function') {
642
- e[k] = def[k];
643
- }
644
- }
645
- if (def.init) def.init(e);
646
- }
647
-
648
- // Apply custom props
649
- if (props) {
650
- for (var k in props) {
651
- e[k] = props[k];
652
- }
653
- }
654
-
655
- game.entities.push(e);
656
- return e;
657
- }
658
-
659
- function updateEntities() {
660
- game.entities.forEach(function(e) {
661
- if (!e.dead) {
662
- var def = entityTypes[e.type];
663
- if (def && def.update) {
664
- def.update(e);
665
- } else {
666
- // Default update
667
- e.x += e.dx;
668
- e.y += e.dy;
669
- e.dx *= 0.9;
670
- e.dy *= 0.9;
671
- }
672
- }
673
- });
674
- }
675
-
676
- function drawEntities() {
677
- // Sort by Y
678
- game.entities.sort(function(a, b) { return a.y - b.y; });
679
-
680
- game.entities.forEach(function(e) {
681
- if (!e.dead) {
682
- var def = entityTypes[e.type];
683
- if (def && def.draw) {
684
- def.draw(e);
685
- } else {
686
- spr(e.spr, e.x - game.cam.x, e.y - game.cam.y, 0, 1, e.flip);
687
- }
688
- }
689
- });
690
- }
691
-
692
- function cleanupDead() {
693
- game.entities = game.entities.filter(function(e) { return !e.dead; });
694
- }
695
-
696
- function checkCollisions() {
697
- for (var i = 0; i < game.entities.length; i++) {
698
- var a = game.entities[i];
699
- if (!a.dead && a.solid) {
700
- for (var j = i + 1; j < game.entities.length; j++) {
701
- var b = game.entities[j];
702
- if (!b.dead && b.solid && collides(a, b)) {
703
- var defA = entityTypes[a.type];
704
- var defB = entityTypes[b.type];
705
- if (defA && defA.onCollision) defA.onCollision(a, b);
706
- if (defB && defB.onCollision) defB.onCollision(b, a);
707
- }
708
- }
709
- }
710
- }
711
- }
712
-
713
- function collides(a, b) {
714
- return a.x < b.x + b.w &&
715
- a.x + a.w > b.x &&
716
- a.y < b.y + b.h &&
717
- a.y + a.h > b.y;
718
- }
719
-
720
- function drawMap() {
721
- map(0, 0, 30, 17, 0, 0, 0);
722
- }
723
-
724
- function drawUI() {
725
- print("Nice2Dev", 2, 2, 12);
726
- }
727
-
728
- function drawDebug() {
729
- rect(0, 0, 80, 16, 0);
730
- print("ent:" + game.entities.length, 2, 2, 12);
731
- }
687
+ }
688
+ }
689
+
690
+ function collides(a, b) {
691
+ return a.x < b.x + b.w &&
692
+ a.x + a.w > b.x &&
693
+ a.y < b.y + b.h &&
694
+ a.y + a.h > b.y;
695
+ }
696
+
697
+ function drawMap() {
698
+ map(0, 0, 30, 17, 0, 0, 0);
699
+ }
700
+
701
+ function drawUI() {
702
+ print("Nice2Dev", 2, 2, 12);
703
+ }
704
+
705
+ function drawDebug() {
706
+ rect(0, 0, 80, 16, 0);
707
+ print("ent:" + game.entities.length, 2, 2, 12);
708
+ }
732
709
  `);
733
- // Entity types
734
- lines.push('// Entity Types');
735
- lines.push('var entityTypes = {};');
736
- lines.push('');
737
- // Scenes
738
- lines.push('// Scenes');
739
- lines.push('var scenes = [');
740
- for (const scene of project.scenes) {
741
- const sceneName = scene.name.toLowerCase().replace(/[^a-z0-9_]/g, '_');
742
- lines.push(` {`);
743
- lines.push(` name: "${sceneName}",`);
744
- lines.push(` entities: [`);
745
- for (const entity of scene.entities) {
746
- const typeName = (entity.name ?? entity.id).toLowerCase().replace(/[^a-z0-9_]/g, '_');
747
- const pos = entity.position ?? { x: 0, y: 0 };
748
- const x = Math.floor((pos.x / project.settings.resolution.width) * TIC80_WIDTH);
749
- const y = Math.floor((pos.y / project.settings.resolution.height) * TIC80_HEIGHT);
750
- lines.push(` {type: "${typeName}", x: ${x}, y: ${y}},`);
751
- }
752
- lines.push(` ]`);
753
- lines.push(` },`);
754
- }
755
- lines.push('];');
756
- lines.push('');
757
- lines.push(`
758
- function loadScene(index) {
759
- game.entities = [];
760
- var scene = scenes[index - 1];
761
- if (scene) {
762
- scene.entities.forEach(function(e) {
763
- makeEntity(e.type, e.x, e.y);
764
- });
765
- trace("Loaded scene: " + scene.name);
766
- }
767
- }
710
+ lines.push("// Entity Types");
711
+ lines.push("var entityTypes = {};");
712
+ lines.push("");
713
+ lines.push("// Scenes");
714
+ lines.push("var scenes = [");
715
+ for (const scene of project.scenes) {
716
+ const sceneName = scene.name.toLowerCase().replace(/[^a-z0-9_]/g, "_");
717
+ lines.push(` {`);
718
+ lines.push(` name: "${sceneName}",`);
719
+ lines.push(` entities: [`);
720
+ for (const entity of scene.entities) {
721
+ const typeName = (entity.name ?? entity.id).toLowerCase().replace(/[^a-z0-9_]/g, "_");
722
+ const pos = entity.position ?? { x: 0, y: 0 };
723
+ const x = Math.floor(pos.x / project.settings.resolution.width * TIC80_WIDTH);
724
+ const y = Math.floor(pos.y / project.settings.resolution.height * TIC80_HEIGHT);
725
+ lines.push(` {type: "${typeName}", x: ${x}, y: ${y}},`);
726
+ }
727
+ lines.push(` ]`);
728
+ lines.push(` },`);
729
+ }
730
+ lines.push("];");
731
+ lines.push("");
732
+ lines.push(`
733
+ function loadScene(index) {
734
+ game.entities = [];
735
+ var scene = scenes[index - 1];
736
+ if (scene) {
737
+ scene.entities.forEach(function(e) {
738
+ makeEntity(e.type, e.x, e.y);
739
+ });
740
+ trace("Loaded scene: " + scene.name);
741
+ }
742
+ }
768
743
  `);
769
- return lines.join('\n');
744
+ return lines.join("\n");
745
+ }
746
+ /* ── Moonscript Code Generation ─────────────────────────────── */
747
+ generateMoonscriptCode(project, options) {
748
+ const lines = [];
749
+ lines.push(`-- ${project.name} - TIC-80 Moonscript`);
750
+ lines.push("-- Generated from Nice2Dev");
751
+ lines.push("");
752
+ lines.push(`
753
+ -- Game State
754
+ export game = {
755
+ t: 0
756
+ state: "play"
757
+ cam: {x: 0, y: 0}
758
+ entities: {}
759
+ debug: ${options.platformOptions?.includeDebug ?? false}
760
+ }
761
+
762
+ -- Constants
763
+ SCREEN_W = ${TIC80_WIDTH}
764
+ SCREEN_H = ${TIC80_HEIGHT}
765
+
766
+ -- Boot
767
+ export BOOT = ->
768
+ trace "${project.name} v${project.version}"
769
+ load_scene 1
770
+
771
+ -- Main Loop
772
+ export TIC = ->
773
+ game.t += 1
774
+
775
+ if game.state == "play"
776
+ update_entities!
777
+ check_collisions!
778
+ cleanup_dead!
779
+
780
+ cls 0
781
+ draw_map!
782
+ draw_entities!
783
+ draw_ui!
784
+
785
+ draw_debug! if game.debug
786
+
787
+ -- Entity System
788
+ entity_types = {}
789
+
790
+ make_entity = (type_name, x, y, props) ->
791
+ e = {
792
+ type: type_name
793
+ x: x or 0
794
+ y: y or 0
795
+ dx: 0
796
+ dy: 0
797
+ w: 8
798
+ h: 8
799
+ spr: 0
800
+ flip: 0
801
+ dead: false
802
+ solid: false
803
+ tags: {}
804
+ }
805
+
806
+ -- Apply type defaults
807
+ if entity_types[type_name]
808
+ def = entity_types[type_name]
809
+ for k, v in pairs def
810
+ e[k] = v if type(v) != "function"
811
+ def.init(e) if def.init
812
+
813
+ -- Apply props
814
+ if props
815
+ for k, v in pairs props
816
+ e[k] = v
817
+
818
+ table.insert game.entities, e
819
+ e
820
+
821
+ update_entities = ->
822
+ for e in *game.entities
823
+ unless e.dead
824
+ def = entity_types[e.type]
825
+ if def and def.update
826
+ def.update e
827
+ else
828
+ e.x += e.dx
829
+ e.y += e.dy
830
+ e.dx *= 0.9
831
+ e.dy *= 0.9
832
+
833
+ draw_entities = ->
834
+ table.sort game.entities, (a, b) -> a.y < b.y
835
+ for e in *game.entities
836
+ unless e.dead
837
+ def = entity_types[e.type]
838
+ if def and def.draw
839
+ def.draw e
840
+ else
841
+ spr e.spr, e.x - game.cam.x, e.y - game.cam.y, 0, 1, e.flip
842
+
843
+ cleanup_dead = ->
844
+ for i = #game.entities, 1, -1
845
+ table.remove game.entities, i if game.entities[i].dead
846
+
847
+ check_collisions = ->
848
+ for i = 1, #game.entities
849
+ a = game.entities[i]
850
+ if not a.dead and a.solid
851
+ for j = i + 1, #game.entities
852
+ b = game.entities[j]
853
+ if not b.dead and b.solid and collides(a, b)
854
+ def_a = entity_types[a.type]
855
+ def_b = entity_types[b.type]
856
+ def_a.on_collision(a, b) if def_a and def_a.on_collision
857
+ def_b.on_collision(b, a) if def_b and def_b.on_collision
858
+
859
+ collides = (a, b) ->
860
+ a.x < b.x + b.w and
861
+ a.x + a.w > b.x and
862
+ a.y < b.y + b.h and
863
+ a.y + a.h > b.y
864
+
865
+ -- Scenes
866
+ scenes = {
867
+ ${project.scenes.map((scene, _i) => {
868
+ const sceneName = scene.name.toLowerCase().replace(/[^a-z0-9_]/g, "_");
869
+ return ` {
870
+ name: "${sceneName}"
871
+ entities: {
872
+ ${scene.entities.map((entity) => {
873
+ const typeName = (entity.name ?? entity.id).toLowerCase().replace(/[^a-z0-9_]/g, "_");
874
+ const pos = entity.position ?? { x: 0, y: 0 };
875
+ const x = Math.floor(pos.x / project.settings.resolution.width * TIC80_WIDTH);
876
+ const y = Math.floor(pos.y / project.settings.resolution.height * TIC80_HEIGHT);
877
+ return ` {type: "${typeName}", x: ${x}, y: ${y}}`;
878
+ }).join("\n")}
770
879
  }
771
- /* ── Moonscript Code Generation ─────────────────────────────── */
772
- generateMoonscriptCode(project, options) {
773
- const lines = [];
774
- lines.push(`-- ${project.name} - TIC-80 Moonscript`);
775
- lines.push('-- Generated from Nice2Dev');
776
- lines.push('');
777
- lines.push(`
778
- -- Game State
779
- export game = {
780
- t: 0
781
- state: "play"
782
- cam: {x: 0, y: 0}
783
- entities: {}
784
- debug: ${options.platformOptions?.includeDebug ?? false}
785
- }
786
-
787
- -- Constants
788
- SCREEN_W = ${TIC80_WIDTH}
789
- SCREEN_H = ${TIC80_HEIGHT}
790
-
791
- -- Boot
792
- export BOOT = ->
793
- trace "${project.name} v${project.version}"
794
- load_scene 1
795
-
796
- -- Main Loop
797
- export TIC = ->
798
- game.t += 1
799
-
800
- if game.state == "play"
801
- update_entities!
802
- check_collisions!
803
- cleanup_dead!
804
-
805
- cls 0
806
- draw_map!
807
- draw_entities!
808
- draw_ui!
809
-
810
- draw_debug! if game.debug
811
-
812
- -- Entity System
813
- entity_types = {}
814
-
815
- make_entity = (type_name, x, y, props) ->
816
- e = {
817
- type: type_name
818
- x: x or 0
819
- y: y or 0
820
- dx: 0
821
- dy: 0
822
- w: 8
823
- h: 8
824
- spr: 0
825
- flip: 0
826
- dead: false
827
- solid: false
828
- tags: {}
829
- }
830
-
831
- -- Apply type defaults
832
- if entity_types[type_name]
833
- def = entity_types[type_name]
834
- for k, v in pairs def
835
- e[k] = v if type(v) != "function"
836
- def.init(e) if def.init
837
-
838
- -- Apply props
839
- if props
840
- for k, v in pairs props
841
- e[k] = v
842
-
843
- table.insert game.entities, e
844
- e
845
-
846
- update_entities = ->
847
- for e in *game.entities
848
- unless e.dead
849
- def = entity_types[e.type]
850
- if def and def.update
851
- def.update e
852
- else
853
- e.x += e.dx
854
- e.y += e.dy
855
- e.dx *= 0.9
856
- e.dy *= 0.9
857
-
858
- draw_entities = ->
859
- table.sort game.entities, (a, b) -> a.y < b.y
860
- for e in *game.entities
861
- unless e.dead
862
- def = entity_types[e.type]
863
- if def and def.draw
864
- def.draw e
865
- else
866
- spr e.spr, e.x - game.cam.x, e.y - game.cam.y, 0, 1, e.flip
867
-
868
- cleanup_dead = ->
869
- for i = #game.entities, 1, -1
870
- table.remove game.entities, i if game.entities[i].dead
871
-
872
- check_collisions = ->
873
- for i = 1, #game.entities
874
- a = game.entities[i]
875
- if not a.dead and a.solid
876
- for j = i + 1, #game.entities
877
- b = game.entities[j]
878
- if not b.dead and b.solid and collides(a, b)
879
- def_a = entity_types[a.type]
880
- def_b = entity_types[b.type]
881
- def_a.on_collision(a, b) if def_a and def_a.on_collision
882
- def_b.on_collision(b, a) if def_b and def_b.on_collision
883
-
884
- collides = (a, b) ->
885
- a.x < b.x + b.w and
886
- a.x + a.w > b.x and
887
- a.y < b.y + b.h and
888
- a.y + a.h > b.y
889
-
890
- -- Scenes
891
- scenes = {
892
- ${project.scenes
893
- .map((scene, _i) => {
894
- const sceneName = scene.name.toLowerCase().replace(/[^a-z0-9_]/g, '_');
895
- return ` {
896
- name: "${sceneName}"
897
- entities: {
898
- ${scene.entities
899
- .map((entity) => {
900
- const typeName = (entity.name ?? entity.id).toLowerCase().replace(/[^a-z0-9_]/g, '_');
901
- const pos = entity.position ?? { x: 0, y: 0 };
902
- const x = Math.floor((pos.x / project.settings.resolution.width) * TIC80_WIDTH);
903
- const y = Math.floor((pos.y / project.settings.resolution.height) * TIC80_HEIGHT);
904
- return ` {type: "${typeName}", x: ${x}, y: ${y}}`;
905
- })
906
- .join('\n')}
907
- }
908
880
  }`;
909
- })
910
- .join('\n')}
911
- }
912
-
913
- load_scene = (index) ->
914
- game.entities = {}
915
- scene = scenes[index]
916
- if scene
917
- for e in *scene.entities
918
- make_entity e.type, e.x, e.y
919
- trace "Loaded scene: " .. scene.name
920
-
921
- -- Utilities
922
- draw_map = -> map 0, 0, 30, 17, 0, 0, 0
923
- draw_ui = -> print "Nice2Dev", 2, 2, 12
924
- draw_debug = ->
925
- rect 0, 0, 80, 16, 0
926
- print "ent:" .. #game.entities, 2, 2, 12
881
+ }).join("\n")}
882
+ }
883
+
884
+ load_scene = (index) ->
885
+ game.entities = {}
886
+ scene = scenes[index]
887
+ if scene
888
+ for e in *scene.entities
889
+ make_entity e.type, e.x, e.y
890
+ trace "Loaded scene: " .. scene.name
891
+
892
+ -- Utilities
893
+ draw_map = -> map 0, 0, 30, 17, 0, 0, 0
894
+ draw_ui = -> print "Nice2Dev", 2, 2, 12
895
+ draw_debug = ->
896
+ rect 0, 0, 80, 16, 0
897
+ print "ent:" .. #game.entities, 2, 2, 12
927
898
  `);
928
- return lines.join('\n');
899
+ return lines.join("\n");
900
+ }
901
+ /* ── Wren Code Generation ───────────────────────────────────── */
902
+ generateWrenCode(project, _options) {
903
+ return `// ${project.name} - TIC-80 Wren
904
+ // Generated from Nice2Dev
905
+
906
+ class Game {
907
+ static t { __t }
908
+ static t=(v) { __t = v }
909
+ static state { __state }
910
+ static state=(v) { __state = v }
911
+ static entities { __entities }
912
+ static entities=(v) { __entities = v }
913
+
914
+ static init() {
915
+ __t = 0
916
+ __state = "play"
917
+ __entities = []
918
+ }
919
+ }
920
+
921
+ class TIC {
922
+ static BOOT() {
923
+ TIC.trace("${project.name} v${project.version}")
924
+ Game.init()
925
+ SceneManager.loadScene(1)
926
+ }
927
+
928
+ static TIC() {
929
+ Game.t = Game.t + 1
930
+
931
+ if (Game.state == "play") {
932
+ EntityManager.update()
933
+ EntityManager.draw()
934
+ UI.draw()
929
935
  }
930
- /* ── Wren Code Generation ───────────────────────────────────── */
931
- generateWrenCode(project, _options) {
932
- return `// ${project.name} - TIC-80 Wren
933
- // Generated from Nice2Dev
934
-
935
- class Game {
936
- static t { __t }
937
- static t=(v) { __t = v }
938
- static state { __state }
939
- static state=(v) { __state = v }
940
- static entities { __entities }
941
- static entities=(v) { __entities = v }
942
-
943
- static init() {
944
- __t = 0
945
- __state = "play"
946
- __entities = []
947
- }
948
- }
949
-
950
- class TIC {
951
- static BOOT() {
952
- TIC.trace("${project.name} v${project.version}")
953
- Game.init()
954
- SceneManager.loadScene(1)
955
- }
956
-
957
- static TIC() {
958
- Game.t = Game.t + 1
959
-
960
- if (Game.state == "play") {
961
- EntityManager.update()
962
- EntityManager.draw()
963
- UI.draw()
964
- }
965
- }
966
- }
967
-
968
- class EntityManager {
969
- static update() {
970
- for (entity in Game.entities) {
971
- if (!entity.dead) {
972
- entity.update()
973
- }
974
- }
975
- // Cleanup dead
976
- Game.entities = Game.entities.where { |e| !e.dead }.toList
977
- }
978
-
979
- static draw() {
980
- Game.entities.sort { |a, b| a.y < b.y }
981
- for (entity in Game.entities) {
982
- if (!entity.dead) {
983
- entity.draw()
984
- }
985
- }
986
- }
987
- }
988
-
989
- class Entity {
990
- x { _x }
991
- x=(v) { _x = v }
992
- y { _y }
993
- y=(v) { _y = v }
994
- dead { _dead }
995
- dead=(v) { _dead = v }
996
- spr { _spr }
997
-
998
- construct new(x, y, spr) {
999
- _x = x
1000
- _y = y
1001
- _spr = spr
1002
- _dead = false
1003
- }
1004
-
1005
- update() {
1006
- // Override in subclass
1007
- }
1008
-
1009
- draw() {
1010
- TIC.spr(_spr, _x, _y)
1011
- }
1012
-
1013
- kill() {
1014
- _dead = true
1015
- }
1016
- }
1017
-
1018
- class SceneManager {
1019
- static scenes { [
1020
- ${project.scenes
1021
- .map((scene) => {
1022
- const sceneName = scene.name.toLowerCase().replace(/[^a-z0-9_]/g, '_');
1023
- return ` Scene.new("${sceneName}", [
1024
- ${scene.entities
1025
- .map((entity) => {
1026
- const pos = entity.position ?? { x: 0, y: 0 };
1027
- const x = Math.floor((pos.x / project.settings.resolution.width) * TIC80_WIDTH);
1028
- const y = Math.floor((pos.y / project.settings.resolution.height) * TIC80_HEIGHT);
1029
- return ` [${x}, ${y}, 1]`;
1030
- })
1031
- .join(',\n')}
936
+ }
937
+ }
938
+
939
+ class EntityManager {
940
+ static update() {
941
+ for (entity in Game.entities) {
942
+ if (!entity.dead) {
943
+ entity.update()
944
+ }
945
+ }
946
+ // Cleanup dead
947
+ Game.entities = Game.entities.where { |e| !e.dead }.toList
948
+ }
949
+
950
+ static draw() {
951
+ Game.entities.sort { |a, b| a.y < b.y }
952
+ for (entity in Game.entities) {
953
+ if (!entity.dead) {
954
+ entity.draw()
955
+ }
956
+ }
957
+ }
958
+ }
959
+
960
+ class Entity {
961
+ x { _x }
962
+ x=(v) { _x = v }
963
+ y { _y }
964
+ y=(v) { _y = v }
965
+ dead { _dead }
966
+ dead=(v) { _dead = v }
967
+ spr { _spr }
968
+
969
+ construct new(x, y, spr) {
970
+ _x = x
971
+ _y = y
972
+ _spr = spr
973
+ _dead = false
974
+ }
975
+
976
+ update() {
977
+ // Override in subclass
978
+ }
979
+
980
+ draw() {
981
+ TIC.spr(_spr, _x, _y)
982
+ }
983
+
984
+ kill() {
985
+ _dead = true
986
+ }
987
+ }
988
+
989
+ class SceneManager {
990
+ static scenes { [
991
+ ${project.scenes.map((scene) => {
992
+ const sceneName = scene.name.toLowerCase().replace(/[^a-z0-9_]/g, "_");
993
+ return ` Scene.new("${sceneName}", [
994
+ ${scene.entities.map((entity) => {
995
+ const pos = entity.position ?? { x: 0, y: 0 };
996
+ const x = Math.floor(pos.x / project.settings.resolution.width * TIC80_WIDTH);
997
+ const y = Math.floor(pos.y / project.settings.resolution.height * TIC80_HEIGHT);
998
+ return ` [${x}, ${y}, 1]`;
999
+ }).join(",\n")}
1032
1000
  ])`;
1033
- })
1034
- .join(',\n')}
1035
- ] }
1036
-
1037
- static loadScene(index) {
1038
- Game.entities = []
1039
- var scene = scenes[index - 1]
1040
- if (scene != null) {
1041
- for (data in scene.entities) {
1042
- Game.entities.add(Entity.new(data[0], data[1], data[2]))
1043
- }
1044
- TIC.trace("Loaded: %(scene.name)")
1045
- }
1046
- }
1047
- }
1048
-
1049
- class Scene {
1050
- name { _name }
1051
- entities { _entities }
1052
-
1053
- construct new(name, entities) {
1054
- _name = name
1055
- _entities = entities
1056
- }
1057
- }
1058
-
1059
- class UI {
1060
- static draw() {
1061
- TIC.print("Nice2Dev", 2, 2, 12)
1062
- }
1063
- }
1064
- `;
1001
+ }).join(",\n")}
1002
+ ] }
1003
+
1004
+ static loadScene(index) {
1005
+ Game.entities = []
1006
+ var scene = scenes[index - 1]
1007
+ if (scene != null) {
1008
+ for (data in scene.entities) {
1009
+ Game.entities.add(Entity.new(data[0], data[1], data[2]))
1010
+ }
1011
+ TIC.trace("Loaded: %(scene.name)")
1065
1012
  }
1066
- /* ── Data Sections ──────────────────────────────────────────── */
1067
- generateSpritesSection(_project) {
1068
- // TIC-80 sprites: each line represents 8 pixels (1 byte = 2 pixels)
1069
- // 256 sprites in 16x16 grid = 128x128 pixels
1070
- const lines = [];
1071
- lines.push('-- <TILES>');
1072
- // Generate basic placeholder sprites
1073
- for (let sprRow = 0; sprRow < 16; sprRow++) {
1074
- for (let py = 0; py < 8; py++) {
1075
- let line = '-- ';
1076
- for (let sprCol = 0; sprCol < 16; sprCol++) {
1077
- const sprIndex = sprRow * 16 + sprCol;
1078
- for (let px = 0; px < 8; px++) {
1079
- let pixel = 0;
1080
- // Sprite 1: Player
1081
- if (sprIndex === 1) {
1082
- if (py >= 1 && py <= 6 && px >= 1 && px <= 6) {
1083
- pixel =
1084
- py === 2 && (px === 2 || px === 5)
1085
- ? 9 // eyes
1086
- : py === 4 && px >= 2 && px <= 5
1087
- ? 2 // mouth
1088
- : 4; // body
1089
- }
1090
- }
1091
- // Sprite 17: Enemy
1092
- else if (sprIndex === 17) {
1093
- if (py >= 1 && py <= 6 && px >= 1 && px <= 6) {
1094
- pixel = 2; // red
1095
- if (py === 2 && (px === 2 || px === 5)) {
1096
- pixel = 12;
1097
- } // eyes
1098
- }
1099
- }
1100
- // Sprite 33: Item
1101
- else if (sprIndex === 33) {
1102
- if (px >= 2 && px <= 5 && py >= 1 && py <= 6) {
1103
- pixel = 4;
1104
- } // yellow
1105
- if (py >= 2 && py <= 5 && (px === 1 || px === 6)) {
1106
- pixel = 4;
1107
- }
1108
- if (px >= 3 && px <= 4 && py >= 3 && py <= 4) {
1109
- pixel = 3;
1110
- } // orange center
1111
- }
1112
- line += pixel.toString(16);
1113
- }
1013
+ }
1014
+ }
1015
+
1016
+ class Scene {
1017
+ name { _name }
1018
+ entities { _entities }
1019
+
1020
+ construct new(name, entities) {
1021
+ _name = name
1022
+ _entities = entities
1023
+ }
1024
+ }
1025
+
1026
+ class UI {
1027
+ static draw() {
1028
+ TIC.print("Nice2Dev", 2, 2, 12)
1029
+ }
1030
+ }
1031
+ `;
1032
+ }
1033
+ /* ── Data Sections ──────────────────────────────────────────── */
1034
+ generateSpritesSection(_project) {
1035
+ const lines = [];
1036
+ lines.push("-- <TILES>");
1037
+ for (let sprRow = 0; sprRow < 16; sprRow++) {
1038
+ for (let py = 0; py < 8; py++) {
1039
+ let line = "-- ";
1040
+ for (let sprCol = 0; sprCol < 16; sprCol++) {
1041
+ const sprIndex = sprRow * 16 + sprCol;
1042
+ for (let px = 0; px < 8; px++) {
1043
+ let pixel = 0;
1044
+ if (sprIndex === 1) {
1045
+ if (py >= 1 && py <= 6 && px >= 1 && px <= 6) {
1046
+ pixel = py === 2 && (px === 2 || px === 5) ? 9 : py === 4 && px >= 2 && px <= 5 ? 2 : 4;
1047
+ }
1048
+ } else if (sprIndex === 17) {
1049
+ if (py >= 1 && py <= 6 && px >= 1 && px <= 6) {
1050
+ pixel = 2;
1051
+ if (py === 2 && (px === 2 || px === 5)) {
1052
+ pixel = 12;
1114
1053
  }
1115
- lines.push(line);
1054
+ }
1055
+ } else if (sprIndex === 33) {
1056
+ if (px >= 2 && px <= 5 && py >= 1 && py <= 6) {
1057
+ pixel = 4;
1058
+ }
1059
+ if (py >= 2 && py <= 5 && (px === 1 || px === 6)) {
1060
+ pixel = 4;
1061
+ }
1062
+ if (px >= 3 && px <= 4 && py >= 3 && py <= 4) {
1063
+ pixel = 3;
1064
+ }
1116
1065
  }
1066
+ line += pixel.toString(16);
1067
+ }
1117
1068
  }
1118
- lines.push('-- </TILES>');
1119
- return lines.join('\n');
1069
+ lines.push(line);
1070
+ }
1120
1071
  }
1121
- generateMapSection(_project) {
1122
- const lines = [];
1123
- lines.push('-- <MAP>');
1124
- // 240x136 / 8 = 30x17 tiles
1125
- for (let y = 0; y < 136; y++) {
1126
- let line = '-- ';
1127
- for (let x = 0; x < 240; x++) {
1128
- line += '0';
1129
- }
1130
- lines.push(line);
1131
- }
1132
- lines.push('-- </MAP>');
1133
- return lines.join('\n');
1072
+ lines.push("-- </TILES>");
1073
+ return lines.join("\n");
1074
+ }
1075
+ generateMapSection(_project) {
1076
+ const lines = [];
1077
+ lines.push("-- <MAP>");
1078
+ for (let y = 0; y < 136; y++) {
1079
+ let line = "-- ";
1080
+ for (let x = 0; x < 240; x++) {
1081
+ line += "0";
1082
+ }
1083
+ lines.push(line);
1134
1084
  }
1135
- generateWavesSection(_project, _options) {
1136
- return `-- <WAVES>
1137
- -- 000:00000000ffffffff00000000ffffffff
1138
- -- 001:0123456789abcdeffedcba9876543210
1139
- -- 002:0123456789abcdef0123456789abcdef
1140
- -- 003:fedcba9876543210fedcba9876543210
1085
+ lines.push("-- </MAP>");
1086
+ return lines.join("\n");
1087
+ }
1088
+ generateWavesSection(_project, _options) {
1089
+ return `-- <WAVES>
1090
+ -- 000:00000000ffffffff00000000ffffffff
1091
+ -- 001:0123456789abcdeffedcba9876543210
1092
+ -- 002:0123456789abcdef0123456789abcdef
1093
+ -- 003:fedcba9876543210fedcba9876543210
1141
1094
  -- </WAVES>`;
1142
- }
1143
- generateSfxSection(_project) {
1144
- return `-- <SFX>
1145
- -- 000:000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000304000000000
1095
+ }
1096
+ generateSfxSection(_project) {
1097
+ return `-- <SFX>
1098
+ -- 000:000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000304000000000
1146
1099
  -- </SFX>`;
1147
- }
1148
- generateMusicSection(_project) {
1149
- return `-- <PATTERNS>
1150
- -- 000:400000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
1151
- -- </PATTERNS>
1152
-
1153
- -- <TRACKS>
1154
- -- 000:180000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
1100
+ }
1101
+ generateMusicSection(_project) {
1102
+ return `-- <PATTERNS>
1103
+ -- 000:400000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
1104
+ -- </PATTERNS>
1105
+
1106
+ -- <TRACKS>
1107
+ -- 000:180000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
1155
1108
  -- </TRACKS>`;
1156
- }
1157
- generatePaletteSection() {
1158
- return `-- <PALETTE>
1159
- -- 000:1a1c2c5d275db13e53ef7d57ffcd75a7f07038b764257179293 66f3b5dc941a6f673eff7f4f4f494b0c2566c86333c57
1109
+ }
1110
+ generatePaletteSection() {
1111
+ return `-- <PALETTE>
1112
+ -- 000:1a1c2c5d275db13e53ef7d57ffcd75a7f07038b764257179293 66f3b5dc941a6f673eff7f4f4f494b0c2566c86333c57
1160
1113
  -- </PALETTE>`;
1114
+ }
1115
+ /* ── Color Utility ──────────────────────────────────────────── */
1116
+ getClosestTic80Color(hex) {
1117
+ const cleanHex = hex.replace("#", "").toLowerCase();
1118
+ const r = parseInt(cleanHex.substring(0, 2), 16);
1119
+ const g = parseInt(cleanHex.substring(2, 4), 16);
1120
+ const b = parseInt(cleanHex.substring(4, 6), 16);
1121
+ let closestIndex = 0;
1122
+ let closestDist = Infinity;
1123
+ for (let i = 0; i < TIC80_PALETTE.length; i++) {
1124
+ const palHex = TIC80_PALETTE[i].replace("#", "");
1125
+ const pr = parseInt(palHex.substring(0, 2), 16);
1126
+ const pg = parseInt(palHex.substring(2, 4), 16);
1127
+ const pb = parseInt(palHex.substring(4, 6), 16);
1128
+ const dist = Math.sqrt(Math.pow(r - pr, 2) + Math.pow(g - pg, 2) + Math.pow(b - pb, 2));
1129
+ if (dist < closestDist) {
1130
+ closestDist = dist;
1131
+ closestIndex = i;
1132
+ }
1161
1133
  }
1162
- /* ── Color Utility ──────────────────────────────────────────── */
1163
- getClosestTic80Color(hex) {
1164
- const cleanHex = hex.replace('#', '').toLowerCase();
1165
- const r = parseInt(cleanHex.substring(0, 2), 16);
1166
- const g = parseInt(cleanHex.substring(2, 4), 16);
1167
- const b = parseInt(cleanHex.substring(4, 6), 16);
1168
- let closestIndex = 0;
1169
- let closestDist = Infinity;
1170
- for (let i = 0; i < TIC80_PALETTE.length; i++) {
1171
- const palHex = TIC80_PALETTE[i].replace('#', '');
1172
- const pr = parseInt(palHex.substring(0, 2), 16);
1173
- const pg = parseInt(palHex.substring(2, 4), 16);
1174
- const pb = parseInt(palHex.substring(4, 6), 16);
1175
- const dist = Math.sqrt(Math.pow(r - pr, 2) + Math.pow(g - pg, 2) + Math.pow(b - pb, 2));
1176
- if (dist < closestDist) {
1177
- closestDist = dist;
1178
- closestIndex = i;
1179
- }
1180
- }
1181
- return closestIndex;
1182
- }
1183
- /* ── README ─────────────────────────────────────────────────── */
1184
- async generateReadme(project, options) {
1185
- const platformOpts = options.platformOptions ?? {};
1186
- const language = platformOpts.language ?? 'lua';
1187
- const safeName = (options.projectName ?? project.name)
1188
- .toLowerCase()
1189
- .replace(/[^a-z0-9_]/g, '_');
1190
- const readme = `# ${project.name} - TIC-80 Export
1191
-
1192
- Generated from Nice2Dev project v${project.version}
1193
-
1194
- ## Requirements
1195
-
1196
- - TIC-80 (Free: https://tic80.com/)
1197
-
1198
- ## Installation
1199
-
1200
- ### Method 1: Load TIC file
1201
- 1. Open TIC-80
1202
- 2. Type: \`load ${safeName}\`
1203
- 3. Press F5 or type \`run\`
1204
-
1205
- ### Method 2: Copy source
1206
- 1. Open TIC-80
1207
- 2. Press Escape to open code editor
1208
- 3. Copy contents of \`${safeName}.${language === 'javascript' ? 'js' : language === 'moonscript' ? 'moon' : language === 'wren' ? 'wren' : 'lua'}\`
1209
- 4. Paste into editor
1210
- 5. Press F5 to run
1211
-
1212
- ## Files
1213
-
1214
- - \`${safeName}.tic\` - TIC-80 cartridge (includes sprites, map, sfx)
1215
- - \`${safeName}.${language === 'javascript' ? 'js' : language === 'moonscript' ? 'moon' : language === 'wren' ? 'wren' : 'lua'}\` - Source code
1216
-
1217
- ## TIC-80 Specs
1218
-
1219
- - **Display**: 240x136 pixels
1220
- - **Colors**: 16 color palette
1221
- - **Sprites**: 256 8x8 sprites
1222
- - **Map**: 240x136 tile map
1223
- - **Sound**: 4 channels, 64 SFX
1224
- - **Music**: 8 tracks, 64 patterns
1225
- - **Languages**: Lua, Moonscript, JavaScript, Wren, Fennel, Squirrel
1226
-
1227
- ## Controls
1228
-
1229
- - Arrow Keys: D-Pad
1230
- - Z / A / J: A button
1231
- - X / S / K: B button
1232
- - Enter: Start
1233
- - Escape: Menu
1234
-
1235
- ## Code Structure (${language})
1236
-
1237
- ${language === 'lua'
1238
- ? `\`\`\`lua
1239
- function BOOT() -- Called once at startup
1240
- function TIC() -- Called every frame (60 FPS)
1241
- function BDR() -- Called before each scanline
1242
- function OVR() -- Called after frame for overlays
1243
- \`\`\`
1244
- `
1245
- : language === 'javascript'
1246
- ? `\`\`\`javascript
1247
- function BOOT() { } // Called once at startup
1248
- function TIC() { } // Called every frame (60 FPS)
1249
- function BDR() { } // Called before each scanline
1250
- \`\`\`
1251
- `
1252
- : language === 'moonscript'
1253
- ? `\`\`\`moonscript
1254
- export BOOT = -> -- Called once at startup
1255
- export TIC = -> -- Called every frame (60 FPS)
1256
- export BDR = -> -- Called before each scanline
1257
- \`\`\`
1258
- `
1259
- : `\`\`\`wren
1260
- class TIC {
1261
- static BOOT() { } // Called once at startup
1262
- static TIC() { } // Called every frame (60 FPS)
1263
- }
1264
- \`\`\`
1265
- `}
1266
-
1267
- ## Scenes
1268
-
1269
- ${project.scenes.map((s, i) => `- Scene ${i + 1}: ${s.name} (${s.entities.length} entities)`).join('\n')}
1270
-
1271
- Load scene: \`load_scene(1)\`
1272
-
1273
- ## Useful TIC-80 Functions
1274
-
1275
- \`\`\`
1276
- cls(color) - Clear screen
1277
- spr(id, x, y) - Draw sprite
1278
- map(x, y, w, h) - Draw map
1279
- print(text, x, y, c) - Print text
1280
- btn(id) - Check button
1281
- sfx(id) - Play sound
1282
- music(track) - Play music
1283
- pix(x, y, c) - Draw pixel
1284
- rect(x, y, w, h, c) - Draw rectangle
1285
- trace(msg) - Debug print
1286
- \`\`\`
1287
-
1288
- ## Debug Mode
1289
-
1290
- ${platformOpts.includeDebug ? 'Debug mode is enabled. Shows entity count and hitboxes.' : 'Debug mode is disabled. Set `game.debug = true` to enable.'}
1291
-
1292
- ## Resources
1293
-
1294
- - TIC-80 Wiki: https://github.com/nesbox/TIC-80/wiki
1295
- - TIC-80 API: https://github.com/nesbox/TIC-80/wiki/API
1296
- - TIC-80 Community: https://tic80.com/play
1297
-
1298
- ## Export Formats
1299
-
1300
- TIC-80 can export to:
1301
- - HTML (Web)
1302
- - Native executables
1303
- - .tic cartridge
1134
+ return closestIndex;
1135
+ }
1136
+ /* ── README ─────────────────────────────────────────────────── */
1137
+ async generateReadme(project, options) {
1138
+ const platformOpts = options.platformOptions ?? {};
1139
+ const language = platformOpts.language ?? "lua";
1140
+ const safeName = (options.projectName ?? project.name).toLowerCase().replace(/[^a-z0-9_]/g, "_");
1141
+ const readme = `# ${project.name} - TIC-80 Export
1142
+
1143
+ Generated from Nice2Dev project v${project.version}
1144
+
1145
+ ## Requirements
1146
+
1147
+ - TIC-80 (Free: https://tic80.com/)
1148
+
1149
+ ## Installation
1150
+
1151
+ ### Method 1: Load TIC file
1152
+ 1. Open TIC-80
1153
+ 2. Type: \`load ${safeName}\`
1154
+ 3. Press F5 or type \`run\`
1155
+
1156
+ ### Method 2: Copy source
1157
+ 1. Open TIC-80
1158
+ 2. Press Escape to open code editor
1159
+ 3. Copy contents of \`${safeName}.${language === "javascript" ? "js" : language === "moonscript" ? "moon" : language === "wren" ? "wren" : "lua"}\`
1160
+ 4. Paste into editor
1161
+ 5. Press F5 to run
1162
+
1163
+ ## Files
1164
+
1165
+ - \`${safeName}.tic\` - TIC-80 cartridge (includes sprites, map, sfx)
1166
+ - \`${safeName}.${language === "javascript" ? "js" : language === "moonscript" ? "moon" : language === "wren" ? "wren" : "lua"}\` - Source code
1167
+
1168
+ ## TIC-80 Specs
1169
+
1170
+ - **Display**: 240x136 pixels
1171
+ - **Colors**: 16 color palette
1172
+ - **Sprites**: 256 8x8 sprites
1173
+ - **Map**: 240x136 tile map
1174
+ - **Sound**: 4 channels, 64 SFX
1175
+ - **Music**: 8 tracks, 64 patterns
1176
+ - **Languages**: Lua, Moonscript, JavaScript, Wren, Fennel, Squirrel
1177
+
1178
+ ## Controls
1179
+
1180
+ - Arrow Keys: D-Pad
1181
+ - Z / A / J: A button
1182
+ - X / S / K: B button
1183
+ - Enter: Start
1184
+ - Escape: Menu
1185
+
1186
+ ## Code Structure (${language})
1187
+
1188
+ ${language === "lua" ? `\`\`\`lua
1189
+ function BOOT() -- Called once at startup
1190
+ function TIC() -- Called every frame (60 FPS)
1191
+ function BDR() -- Called before each scanline
1192
+ function OVR() -- Called after frame for overlays
1193
+ \`\`\`
1194
+ ` : language === "javascript" ? `\`\`\`javascript
1195
+ function BOOT() { } // Called once at startup
1196
+ function TIC() { } // Called every frame (60 FPS)
1197
+ function BDR() { } // Called before each scanline
1198
+ \`\`\`
1199
+ ` : language === "moonscript" ? `\`\`\`moonscript
1200
+ export BOOT = -> -- Called once at startup
1201
+ export TIC = -> -- Called every frame (60 FPS)
1202
+ export BDR = -> -- Called before each scanline
1203
+ \`\`\`
1204
+ ` : `\`\`\`wren
1205
+ class TIC {
1206
+ static BOOT() { } // Called once at startup
1207
+ static TIC() { } // Called every frame (60 FPS)
1208
+ }
1209
+ \`\`\`
1210
+ `}
1211
+
1212
+ ## Scenes
1213
+
1214
+ ${project.scenes.map((s, i) => `- Scene ${i + 1}: ${s.name} (${s.entities.length} entities)`).join("\n")}
1215
+
1216
+ Load scene: \`load_scene(1)\`
1217
+
1218
+ ## Useful TIC-80 Functions
1219
+
1220
+ \`\`\`
1221
+ cls(color) - Clear screen
1222
+ spr(id, x, y) - Draw sprite
1223
+ map(x, y, w, h) - Draw map
1224
+ print(text, x, y, c) - Print text
1225
+ btn(id) - Check button
1226
+ sfx(id) - Play sound
1227
+ music(track) - Play music
1228
+ pix(x, y, c) - Draw pixel
1229
+ rect(x, y, w, h, c) - Draw rectangle
1230
+ trace(msg) - Debug print
1231
+ \`\`\`
1232
+
1233
+ ## Debug Mode
1234
+
1235
+ ${platformOpts.includeDebug ? "Debug mode is enabled. Shows entity count and hitboxes." : "Debug mode is disabled. Set `game.debug = true` to enable."}
1236
+
1237
+ ## Resources
1238
+
1239
+ - TIC-80 Wiki: https://github.com/nesbox/TIC-80/wiki
1240
+ - TIC-80 API: https://github.com/nesbox/TIC-80/wiki/API
1241
+ - TIC-80 Community: https://tic80.com/play
1242
+
1243
+ ## Export Formats
1244
+
1245
+ TIC-80 can export to:
1246
+ - HTML (Web)
1247
+ - Native executables
1248
+ - .tic cartridge
1304
1249
  `;
1305
- this.addTextFile('README.md', readme);
1306
- }
1250
+ this.addTextFile("README.md", readme);
1251
+ }
1307
1252
  }
1308
- /* ── Factory ──────────────────────────────────────────────────── */
1309
1253
  function createTic80Exporter() {
1310
- return new Tic80Exporter();
1254
+ return new Tic80Exporter();
1311
1255
  }
1312
-
1313
1256
  exports.Tic80Exporter = Tic80Exporter;
1314
1257
  exports.createTic80Exporter = createTic80Exporter;