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