@nimbus2d/core 0.0.1

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 (85) hide show
  1. package/dist/index.mjs +18433 -0
  2. package/package.json +39 -0
  3. package/src/base/EventEmitter.js +187 -0
  4. package/src/base/Subsystem.js +183 -0
  5. package/src/base/index.js +6 -0
  6. package/src/core/Application/AppState.js +27 -0
  7. package/src/core/Application/Application.js +480 -0
  8. package/src/core/Application/DefaultConfig.js +63 -0
  9. package/src/core/Application/index.js +7 -0
  10. package/src/core/AssetManager/AssetManager.js +711 -0
  11. package/src/core/AssetManager/AssetTypes.js +108 -0
  12. package/src/core/AssetManager/adapters/IResourceAdapter.js +50 -0
  13. package/src/core/AssetManager/adapters/PixiAdapter.js +90 -0
  14. package/src/core/AssetManager/core/RefCounter.js +167 -0
  15. package/src/core/AssetManager/core/ResourceCache.js +281 -0
  16. package/src/core/AssetManager/core/ResourceEntry.js +191 -0
  17. package/src/core/AssetManager/core/ResourceEventBus.js +127 -0
  18. package/src/core/AssetManager/handlers/IResourceHandler.js +45 -0
  19. package/src/core/AssetManager/index.js +26 -0
  20. package/src/core/AssetManager/plugins/IResourcePlugin.js +56 -0
  21. package/src/core/Camera/Camera.js +534 -0
  22. package/src/core/Camera/CameraTypes.js +59 -0
  23. package/src/core/Camera/index.js +13 -0
  24. package/src/core/ConfigSystem/ConfigLayer.js +230 -0
  25. package/src/core/ConfigSystem/ConfigLayerType.js +31 -0
  26. package/src/core/ConfigSystem/ConfigMerger.js +50 -0
  27. package/src/core/ConfigSystem/ConfigPath.js +96 -0
  28. package/src/core/ConfigSystem/ConfigSystem.js +378 -0
  29. package/src/core/ConfigSystem/ConfigTypes.js +29 -0
  30. package/src/core/ConfigSystem/ConfigWatcher.js +84 -0
  31. package/src/core/ConfigSystem/index.js +19 -0
  32. package/src/core/EventBus/EventBus.js +797 -0
  33. package/src/core/EventBus/Interceptor.js +26 -0
  34. package/src/core/EventBus/PerformanceStats.js +105 -0
  35. package/src/core/EventBus/index.js +7 -0
  36. package/src/core/Lifecycle/Lifecycle.js +265 -0
  37. package/src/core/Lifecycle/LifecycleState.js +31 -0
  38. package/src/core/Lifecycle/index.js +6 -0
  39. package/src/core/Logger/ConsoleHandler.js +55 -0
  40. package/src/core/Logger/LogHandler.js +34 -0
  41. package/src/core/Logger/LogLevel.js +38 -0
  42. package/src/core/Logger/Logger.js +234 -0
  43. package/src/core/Logger/index.js +8 -0
  44. package/src/core/PluginSystem/Plugin.js +156 -0
  45. package/src/core/PluginSystem/PluginEntry.js +102 -0
  46. package/src/core/PluginSystem/PluginState.js +30 -0
  47. package/src/core/PluginSystem/PluginSystem.js +530 -0
  48. package/src/core/PluginSystem/index.js +8 -0
  49. package/src/core/PoolManager/DefaultConfig.js +19 -0
  50. package/src/core/PoolManager/ObjectPool.js +326 -0
  51. package/src/core/PoolManager/PoolManager.js +253 -0
  52. package/src/core/PoolManager/PoolTypes.js +92 -0
  53. package/src/core/PoolManager/index.js +15 -0
  54. package/src/core/SceneManager/FadeTransition.js +64 -0
  55. package/src/core/SceneManager/MaskTransition.js +234 -0
  56. package/src/core/SceneManager/Scene.js +221 -0
  57. package/src/core/SceneManager/SceneManager.js +658 -0
  58. package/src/core/SceneManager/SceneState.js +29 -0
  59. package/src/core/SceneManager/SlideTransition.js +113 -0
  60. package/src/core/SceneManager/Transition.js +102 -0
  61. package/src/core/SceneManager/ZoomTransition.js +119 -0
  62. package/src/core/SceneManager/index.js +12 -0
  63. package/src/core/SpriteGPULayer/SpriteGPULayer.js +321 -0
  64. package/src/core/SpriteGPULayer/SpriteGPULayerTypes.js +49 -0
  65. package/src/core/SpriteGPULayer/index.js +11 -0
  66. package/src/core/Timeline/Clip.js +101 -0
  67. package/src/core/Timeline/DefaultConfig.js +41 -0
  68. package/src/core/Timeline/Easing.js +176 -0
  69. package/src/core/Timeline/Timeline.js +458 -0
  70. package/src/core/Timeline/TimelineTypes.js +89 -0
  71. package/src/core/Timeline/Track.js +202 -0
  72. package/src/core/Timeline/index.js +22 -0
  73. package/src/errors/ConfigError.js +47 -0
  74. package/src/errors/LifecycleError.js +58 -0
  75. package/src/errors/NimbusError.js +43 -0
  76. package/src/errors/PluginError.js +138 -0
  77. package/src/errors/ResourceError.js +166 -0
  78. package/src/errors/SceneError.js +124 -0
  79. package/src/errors/SubsystemError.js +68 -0
  80. package/src/errors/index.js +53 -0
  81. package/src/index.js +86 -0
  82. package/src/types/index.js +141 -0
  83. package/src/utils/MemoryChecker.js +374 -0
  84. package/src/utils/Validator.js +60 -0
  85. package/src/utils/index.js +84 -0
@@ -0,0 +1,480 @@
1
+ // ============================================================================
2
+ // Nimbus2D - Application 启动器
3
+ // ----------------------------------------------------------------------------
4
+ // 职责:
5
+ // 1. 直接包含 PixiJS Application(v8 异步初始化)
6
+ // 2. 分层配置 + 合理默认值
7
+ // 3. async start() + async stop()
8
+ // 4. 提供 use(plugin, options) 注册插件(委托 PluginSystem.register,链式返回 Application)
9
+ // 5. 提供 onError(callback) 全局错误处理(封装 EventBus.on('error'))
10
+ //
11
+ // 继承关系:
12
+ // EventEmitter → Application(启动器,包含所有核心模块,不被 Lifecycle 调度)
13
+ // ============================================================================
14
+
15
+ // 导入 unsafe-eval polyfill(PixiJS v8 官方推荐)
16
+ // 在 CSP 限制环境(如 Electron)中,PixiJS 的 WebGL 着色器编译需要 eval()
17
+ // 此 polyfill 使用预编译着色器替代运行时编译,无需在 CSP 中放开 unsafe-eval
18
+ // 必须在 import { Application } from 'pixi.js' 之前导入
19
+ import 'pixi.js/unsafe-eval'
20
+ import { Application as PixiApplication } from 'pixi.js'
21
+ import { EventEmitter } from '../../base/EventEmitter.js'
22
+ import { AppState } from './AppState.js'
23
+ import { DefaultConfig } from './DefaultConfig.js'
24
+ import { ConfigSystem } from '../ConfigSystem/ConfigSystem.js'
25
+ import { ConfigLayerType } from '../ConfigSystem/ConfigLayerType.js'
26
+ import { EventBus } from '../EventBus/EventBus.js'
27
+ import { Logger } from '../Logger/Logger.js'
28
+ import { Lifecycle } from '../Lifecycle/Lifecycle.js'
29
+ import { AssetManager } from '../AssetManager/AssetManager.js'
30
+ import { SceneManager } from '../SceneManager/SceneManager.js'
31
+ import { PoolManager } from '../PoolManager/PoolManager.js'
32
+ import { PluginSystem } from '../PluginSystem/PluginSystem.js'
33
+ import { MemoryChecker } from '../../utils/MemoryChecker.js'
34
+
35
+ class Application extends EventEmitter {
36
+ /**
37
+ * 构造函数
38
+ * 仅保存用户配置,不创建任何子系统实例
39
+ * @param {Object} [config={}] - 用户配置(合并到 USER 配置层)
40
+ * @param {import('../SceneManager/Scene.js').Scene} [initialScene=null] - 初始场景
41
+ */
42
+ constructor(config = {}, initialScene = null) {
43
+ super()
44
+
45
+ /** @type {AppState} 应用当前状态 */
46
+ this._state = AppState.CREATED
47
+
48
+ /** @type {import('../SceneManager/Scene.js').Scene|null} 初始场景 */
49
+ this._initialScene = initialScene
50
+
51
+ /** @type {Object} 用户初始配置 */
52
+ this._initialConfig = config
53
+
54
+ // 仅保存配置,所有引用 = null,实例在 start() 中创建
55
+ /** @type {import('pixi.js').Application|null} PixiJS 应用实例 */
56
+ this._pixi = null
57
+
58
+ /** @type {ConfigSystem|null} 配置系统 */
59
+ this._config = null
60
+
61
+ /** @type {EventBus|null} 事件总线 */
62
+ this._eventBus = null
63
+
64
+ /** @type {Lifecycle|null} 生命周期管理 */
65
+ this._lifecycle = null
66
+
67
+ /** @type {Logger|null} 日志系统 */
68
+ this._logger = null
69
+
70
+ /** @type {AssetManager|null} 资源管理 */
71
+ this._assetManager = null
72
+
73
+ /** @type {SceneManager|null} 场景管理 */
74
+ this._sceneManager = null
75
+
76
+ /** @type {import('../PoolManager/PoolManager.js').PoolManager|null} 对象池管理 */
77
+ this._poolManager = null
78
+
79
+ /** @type {import('../../utils/MemoryChecker.js').MemoryChecker|null} 内存泄漏检测 */
80
+ this._memoryChecker = null
81
+
82
+ /** @type {PluginSystem|null} 插件管理 */
83
+ this._pluginSystem = null
84
+
85
+ // === 画布尺寸变化检测(四期新增 1.5:app:resize 事件机制)===
86
+ // 用于检测 PixiJS resizeTo 触发的画布尺寸变化,并广播 app:resize 事件
87
+ // 让 Camera 等组件能感知画布尺寸变化并同步更新视口尺寸
88
+ /** @type {number} 上一帧的画布宽度(像素,pixi.screen.width) */
89
+ this._lastScreenWidth = 0
90
+ /** @type {number} 上一帧的画布高度(像素,pixi.screen.height) */
91
+ this._lastScreenHeight = 0
92
+ }
93
+
94
+ // --------------------------------------------------------------------------
95
+ // 状态相关
96
+ // --------------------------------------------------------------------------
97
+
98
+ /** @type {AppState} 应用当前状态 */
99
+ get state() { return this._state }
100
+
101
+ // --------------------------------------------------------------------------
102
+ // 核心模块访问器
103
+ // --------------------------------------------------------------------------
104
+
105
+ /** @type {import('pixi.js').Application|null} PixiJS Application 实例 */
106
+ get pixi() { return this._pixi }
107
+
108
+ /** @type {import('pixi.js').Container|null} PixiJS 根舞台(pixi.stage 别名) */
109
+ get stage() { return this._pixi ? this._pixi.stage : null }
110
+
111
+ /** @type {import('pixi.js').Renderer|null} PixiJS 渲染器(pixi.renderer 别名) */
112
+ get renderer() { return this._pixi ? this._pixi.renderer : null }
113
+
114
+ /** @type {ConfigSystem|null} 配置系统实例 */
115
+ get config() { return this._config }
116
+
117
+ /** @type {EventBus|null} EventBus 实例 */
118
+ get eventBus() { return this._eventBus }
119
+
120
+ /** @type {Lifecycle|null} Lifecycle 实例 */
121
+ get lifecycle() { return this._lifecycle }
122
+
123
+ /** @type {Logger|null} Logger 实例 */
124
+ get logger() { return this._logger }
125
+
126
+ /** @type {AssetManager|null} AssetManager 实例 */
127
+ get assetManager() { return this._assetManager }
128
+
129
+ /** @type {SceneManager|null} SceneManager 实例 */
130
+ get sceneManager() { return this._sceneManager }
131
+
132
+ /** @type {import('../PoolManager/PoolManager.js').PoolManager|null} PoolManager 实例 */
133
+ get poolManager() { return this._poolManager }
134
+
135
+ /** @type {import('../../utils/MemoryChecker.js').MemoryChecker|null} MemoryChecker 实例 */
136
+ get memoryChecker() { return this._memoryChecker }
137
+
138
+ /** @type {PluginSystem|null} PluginSystem 实例 */
139
+ get pluginSystem() { return this._pluginSystem }
140
+
141
+ // --------------------------------------------------------------------------
142
+ // 生命周期方法
143
+ // --------------------------------------------------------------------------
144
+
145
+ /**
146
+ * 异步启动应用
147
+ * 按依赖顺序创建和初始化所有核心模块
148
+ * @returns {Promise<Application>} - 启动完成后返回 this(链式调用)
149
+ * @throws {Error} 启动失败时抛出
150
+ */
151
+ async start() {
152
+ if (this._state !== AppState.CREATED) {
153
+ throw new Error(`Application 已启动或已销毁,当前状态:${this._state}`)
154
+ }
155
+ this._state = AppState.STARTING
156
+
157
+ // 0. WebGPU 检测与渲染器偏好配置(四期新增 1.2)
158
+ // 在 PixiJS init 之前决定 preference,确保 PixiJS 使用正确的后端
159
+ const rendererConfig = this._initialConfig.renderer || {}
160
+ const preferWebGPU = rendererConfig.preferWebGPU === true
161
+ const webgpuFallback = rendererConfig.webgpu?.fallback !== false // 默认 true
162
+ const webgpuDetected = this._detectWebGPU()
163
+
164
+ /** @type {'webgl'|'webgpu'} PixiJS 渲染器偏好 */
165
+ let preference = 'webgl' // 默认 WebGL,保证最大兼容性
166
+ if (preferWebGPU) {
167
+ if (webgpuDetected) {
168
+ preference = 'webgpu'
169
+ } else if (!webgpuFallback) {
170
+ // 不支持 WebGPU 且未启用回退 → 抛错阻止启动
171
+ throw new Error('WebGPU 不被当前浏览器支持,且 renderer.webgpu.fallback=false 已禁用回退')
172
+ }
173
+ // fallback=true 时,preference 保持 'webgl',由 PixiJS 使用 WebGL
174
+ }
175
+
176
+ // 1. 创建并初始化 PixiJS Application(v8 两步异步初始化:new + await init)
177
+ // 最早创建,后续模块构造需要 pixi 引用
178
+ // preference 合并策略:
179
+ // - preferWebGPU=true:由 renderer 配置决定 preference,覆盖用户 pixi.preference
180
+ // (renderer.preferWebGPU 优先级最高,确保 WebGPU 检测逻辑生效)
181
+ // - preferWebGPU=false:不覆盖用户 pixi.preference,尊重用户显式配置
182
+ // (用户可通过 pixi.preference 直接控制后端,向后兼容)
183
+ this._pixi = new PixiApplication()
184
+ const pixiConfig = { ...this._initialConfig.pixi }
185
+ if (preferWebGPU) {
186
+ pixiConfig.preference = preference
187
+ }
188
+ await this._pixi.init(pixiConfig)
189
+
190
+ // 2. 创建所有核心模块实例(按依赖顺序,构造阶段不初始化)
191
+ // 注意:Logger 必须在 Lifecycle 之前创建,因为 Lifecycle 构造函数需要 logger 引用
192
+ this._config = new ConfigSystem()
193
+ this._eventBus = new EventBus()
194
+ this._logger = new Logger(this._eventBus, this._config)
195
+ this._lifecycle = new Lifecycle(this._eventBus, this._logger)
196
+ this._assetManager = new AssetManager(this._eventBus, this._config, this._logger, this._pixi)
197
+ this._sceneManager = new SceneManager(this._eventBus, this._config, this._logger, this._assetManager, this._pixi)
198
+ this._poolManager = new PoolManager(this._eventBus, this._config, this._logger)
199
+ this._pluginSystem = new PluginSystem(this._eventBus, this._config, this._logger, this)
200
+
201
+ // MemoryChecker 不注册到 Lifecycle(是工具类,不是子系统)
202
+ // 在 Lifecycle 初始化后创建,以便自动挂钩已初始化的 PoolManager/AssetManager
203
+
204
+ // 3. 初始化基础设施模块(ConfigSystem 必须先初始化,创建 4 层配置,才能加载配置)
205
+ await this._config.initialize()
206
+ await this._eventBus.initialize()
207
+
208
+ // 4. 加载默认配置 + 用户配置(初始化后才能写入配置层)
209
+ // DefaultConfig 写入 DEFAULT 层(代码内置默认值,freezable=true)
210
+ this._config.loadJSON(DefaultConfig, ConfigLayerType.DEFAULT)
211
+ // 用户配置写入 USER 层(构造参数传入,可覆盖 DEFAULT)
212
+ this._config.loadJSON(this._initialConfig, ConfigLayerType.USER)
213
+
214
+ // 5. 注册子系统到 Lifecycle(注册顺序决定初始化顺序)
215
+ // PoolManager 在 PluginSystem 之前初始化,确保插件安装时池管理器已就绪
216
+ this._lifecycle.registerSubsystem(this._logger)
217
+ this._lifecycle.registerSubsystem(this._assetManager)
218
+ this._lifecycle.registerSubsystem(this._sceneManager)
219
+ this._lifecycle.registerSubsystem(this._poolManager)
220
+ this._lifecycle.registerSubsystem(this._pluginSystem)
221
+
222
+ // 6. 初始化 Lifecycle(内部按顺序初始化所有子系统)
223
+ await this._lifecycle.initialize()
224
+
225
+ // 7. 激活 Lifecycle(关键步骤:使 update() 生效)
226
+ this._lifecycle.activate()
227
+
228
+ // 8. 创建 MemoryChecker(在 Lifecycle 初始化后,以便挂钩已初始化的子系统)
229
+ // MemoryChecker 是工具类,不注册到 Lifecycle,由 Application 直接管理
230
+ this._memoryChecker = new MemoryChecker(this._eventBus, this._config, this._logger)
231
+
232
+ // 开发模式自动挂钩 PoolManager/AssetManager
233
+ if (this._config.get('core.developmentMode') !== false) {
234
+ this._memoryChecker.hookPoolManager(this._poolManager)
235
+ this._memoryChecker.hookAssetManager(this._assetManager)
236
+ this._logger.info('Application.start', '开发模式:MemoryChecker 已自动挂钩 PoolManager/AssetManager')
237
+ }
238
+
239
+ // 9. 启动初始场景(如有)
240
+ if (this._initialScene) {
241
+ await this._sceneManager.register(this._initialScene)
242
+ await this._sceneManager.start(this._initialScene.name)
243
+ }
244
+
245
+ // 10. 添加 Lifecycle.update 到 PixiJS ticker
246
+ // 同时检测画布尺寸变化(PixiJS resizeTo 触发后,pixi.screen.width/height 会变化)
247
+ // 每帧轮询检测,性能开销可忽略(仅两次数值比较)
248
+ this._lastScreenWidth = this._pixi.screen.width
249
+ this._lastScreenHeight = this._pixi.screen.height
250
+ this._pixi.ticker.add((ticker) => {
251
+ const deltaSec = ticker.deltaMS / 1000
252
+ this._lifecycle.update(deltaSec)
253
+ // 检测画布尺寸变化并广播 app:resize 事件
254
+ this._checkResize()
255
+ })
256
+
257
+ // 11. 广播渲染器后端事件(四期新增 1.2)
258
+ // 在所有模块初始化完成后广播,确保订阅者能正常接收
259
+ this._eventBus.emit('renderer:backend', {
260
+ /** 实际使用的后端(基于 PixiJS renderer 实例检测) */
261
+ backend: this._detectRendererBackend(),
262
+ /** 用户配置的偏好 */
263
+ preference,
264
+ /** 是否优先 WebGPU(用户配置) */
265
+ preferWebGPU,
266
+ /** 浏览器是否支持 WebGPU(环境检测) */
267
+ webgpuDetected
268
+ })
269
+
270
+ // 12. 完成启动
271
+ this._state = AppState.RUNNING
272
+ this.emit('ready', this)
273
+ return this
274
+ }
275
+
276
+ /**
277
+ * 异步停止应用(销毁所有资源)
278
+ * 销毁阶段错误不抛出,仅记录到 Logger
279
+ * @returns {Promise<void>}
280
+ */
281
+ async stop() {
282
+ if (this._state === AppState.DESTROYED) return
283
+ this._state = AppState.STOPPING
284
+
285
+ try {
286
+ // 1. 停止 PixiJS ticker
287
+ if (this._pixi) this._pixi.ticker.stop()
288
+
289
+ // 2-9. 反向销毁所有模块(错误不中断流程)
290
+ // 销毁顺序:MemoryChecker → PluginSystem → PoolManager → SceneManager → AssetManager → Logger
291
+ // MemoryChecker 最先销毁(它只是工具类,仅持有引用,不管理资源)
292
+ await this._safeDestroy(this._memoryChecker)
293
+ await this._safeDestroy(this._pluginSystem)
294
+ await this._safeDestroy(this._poolManager)
295
+ await this._safeDestroy(this._sceneManager)
296
+ await this._safeDestroy(this._assetManager)
297
+ await this._safeDestroy(this._logger)
298
+ await this._safeDestroy(this._lifecycle)
299
+ await this._safeDestroy(this._eventBus)
300
+ await this._safeDestroy(this._config)
301
+
302
+ // 9. 销毁 PixiJS Application(v8 签名:destroy(rendererOptions, stageOptions))
303
+ if (this._pixi) {
304
+ try {
305
+ this._pixi.destroy(
306
+ { removeView: true, releaseGlobalResources: true },
307
+ { children: true, texture: true, textureSource: true }
308
+ )
309
+ } catch (e) { /* 忽略 */ }
310
+ }
311
+ } finally {
312
+ this._state = AppState.DESTROYED
313
+ this.emit('destroyed')
314
+ this.removeAllListeners()
315
+ }
316
+ }
317
+
318
+ /**
319
+ * 注册插件(链式调用)
320
+ * 委托给 pluginSystem.register(plugin, options),链式返回 Application 实例
321
+ * @param {import('../PluginSystem/Plugin.js').Plugin} plugin - 插件实例
322
+ * @param {Object} [options={}] - 插件配置
323
+ * @returns {Promise<Application>} - 返回 Promise 支持异步等待安装完成
324
+ */
325
+ async use(plugin, options = {}) {
326
+ if (this._pluginSystem) {
327
+ await this._pluginSystem.register(plugin, options)
328
+ }
329
+ return this
330
+ }
331
+
332
+ /**
333
+ * 注册全局错误回调
334
+ * 内部封装 EventBus.on('error'),自动解构 payload
335
+ * @param {Function} callback - 错误回调 (error: Error, source?: string) => void
336
+ * @returns {Function} - 取消注册函数
337
+ */
338
+ onError(callback) {
339
+ if (!this._eventBus) return () => {}
340
+ return this._eventBus.on('error', (payload) => {
341
+ callback(payload.error, payload.source)
342
+ })
343
+ }
344
+
345
+ /**
346
+ * 静态工厂方法
347
+ * @param {Object} [config={}] - 配置
348
+ * @param {import('../SceneManager/Scene.js').Scene} [initialScene=null] - 初始场景
349
+ * @returns {Promise<Application>} - 启动后的 Application 实例
350
+ */
351
+ static async create(config = {}, initialScene = null) {
352
+ const app = new Application(config, initialScene)
353
+ await app.start()
354
+ return app
355
+ }
356
+
357
+ // --------------------------------------------------------------------------
358
+ // 私有方法
359
+ // --------------------------------------------------------------------------
360
+
361
+ /**
362
+ * 安全销毁模块(销毁阶段错误不中断流程)
363
+ * @param {object} module - 模块实例
364
+ * @returns {Promise<void>}
365
+ * @private
366
+ */
367
+ async _safeDestroy(module) {
368
+ if (!module) return
369
+ try {
370
+ if (typeof module.destroy === 'function') {
371
+ await module.destroy()
372
+ }
373
+ } catch (e) {
374
+ // 销毁阶段错误不抛出,尝试记录到 Logger(若可用)
375
+ try {
376
+ if (this._logger && this._logger.isDestroyed !== true) {
377
+ this._logger.error('Application.stop', e)
378
+ }
379
+ } catch (logErr) { /* 忽略 */ }
380
+ }
381
+ }
382
+
383
+ /**
384
+ * 检测浏览器是否支持 WebGPU(四期新增 1.2)
385
+ * 通过 navigator.gpu 是否存在判断 WebGPU 支持
386
+ *
387
+ * @returns {boolean} true 表示支持 WebGPU
388
+ * @private
389
+ */
390
+ _detectWebGPU() {
391
+ // navigator.gpu 是 WebGPU API 的入口点
392
+ // 在不支持 WebGPU 的浏览器(如 Safari < 16.4、Firefox 未启用)中为 undefined
393
+ // 注意:navigator.gpu 存在不代表一定能正常工作,但作为快速检测足够
394
+ return typeof navigator !== 'undefined' && !!navigator.gpu
395
+ }
396
+
397
+ /**
398
+ * 检测 PixiJS 实际使用的渲染器后端(四期新增 1.2)
399
+ * 通过 PixiJS renderer 实例的 type 字段判断
400
+ *
401
+ * @returns {'webgl'|'webgpu'|'unknown'} 实际使用的后端
402
+ * @private
403
+ */
404
+ _detectRendererBackend() {
405
+ if (!this._pixi || !this._pixi.renderer) return 'unknown'
406
+ // PixiJS v8 中 WebGLRenderer.type === 'webgl',WebGPURenderer.type === 'webgpu'
407
+ // 通过实例的 type 字段判断(PixiJS v8 推荐 API)
408
+ const rendererType = this._pixi.renderer.type
409
+ if (rendererType === 'webgpu') return 'webgpu'
410
+ if (rendererType === 'webgl') return 'webgl'
411
+ return 'unknown'
412
+ }
413
+
414
+ /**
415
+ * 检测画布尺寸变化并广播 app:resize 事件(四期新增 1.5)
416
+ *
417
+ * 工作原理:
418
+ * - PixiJS 的 ResizePlugin 在 window resize 时自动调用 renderer.resize()
419
+ * - renderer.resize() 会更新 pixi.screen.width/height
420
+ * - 本方法每帧轮询 pixi.screen 的尺寸,对比上一帧的值
421
+ * - 若尺寸变化,通过 EventBus 广播 'app:resize' 事件
422
+ *
423
+ * 事件负载(payload):
424
+ * - width: number 新画布宽度(像素)
425
+ * - height: number 新画布高度(像素)
426
+ * - prevWidth: number 上一帧画布宽度(像素)
427
+ * - prevHeight: number 上一帧画布高度(像素)
428
+ *
429
+ * 监听示例:
430
+ * app.eventBus.on('app:resize', ({ width, height }) => {
431
+ * camera.setSize(width, height)
432
+ * })
433
+ *
434
+ * 性能考虑:
435
+ * - 每帧仅执行两次数值比较,开销可忽略
436
+ * - 仅在尺寸变化时才触发事件分发
437
+ *
438
+ * @private
439
+ */
440
+ _checkResize() {
441
+ // 防御性检查:pixi 或 eventBus 可能已销毁
442
+ // 注意:EventBus 内部 emit() 已有 destroyed 检查,此处仅检查引用是否存在
443
+ if (!this._pixi || !this._eventBus) return
444
+
445
+ const screen = this._pixi.screen
446
+ // 快速比较:尺寸未变化时直接返回(每帧命中)
447
+ if (screen.width === this._lastScreenWidth && screen.height === this._lastScreenHeight) {
448
+ return
449
+ }
450
+
451
+ // 尺寸变化:缓存旧值,更新当前值
452
+ const prevWidth = this._lastScreenWidth
453
+ const prevHeight = this._lastScreenHeight
454
+ this._lastScreenWidth = screen.width
455
+ this._lastScreenHeight = screen.height
456
+
457
+ // 广播 app:resize 事件,让 Camera 等订阅者同步更新视口尺寸
458
+ this._eventBus.emit('app:resize', {
459
+ /** 新画布宽度(像素) */
460
+ width: screen.width,
461
+ /** 新画布高度(像素) */
462
+ height: screen.height,
463
+ /** 上一帧画布宽度(像素,便于订阅者计算变化量) */
464
+ prevWidth,
465
+ /** 上一帧画布高度(像素,便于订阅者计算变化量) */
466
+ prevHeight
467
+ })
468
+
469
+ // 同时通过 EventEmitter 触发本地 'resize' 事件(不依赖 EventBus 的监听者)
470
+ // 允许通过 app.on('resize', cb) 直接订阅
471
+ this.emit('resize', {
472
+ width: screen.width,
473
+ height: screen.height,
474
+ prevWidth,
475
+ prevHeight
476
+ })
477
+ }
478
+ }
479
+
480
+ export { Application }
@@ -0,0 +1,63 @@
1
+ // ============================================================================
2
+ // Nimbus2D - 默认配置
3
+ // ----------------------------------------------------------------------------
4
+ // Application 的默认配置,写入 ConfigSystem 的 DEFAULT 层(freezable=true)。
5
+ // ============================================================================
6
+
7
+ /**
8
+ * 默认配置对象
9
+ * @type {Object}
10
+ */
11
+ const DefaultConfig = {
12
+ /** PixiJS 相关配置 */
13
+ pixi: {
14
+ /** 画布宽度 */
15
+ width: 800,
16
+ /** 画布高度 */
17
+ height: 600,
18
+ /** 背景颜色(十六进制) */
19
+ backgroundColor: 0x000000,
20
+ /** 是否抗锯齿 */
21
+ antialias: true,
22
+ /** 是否启用 alpha 通道 */
23
+ alpha: false,
24
+ /** 分辨率(0 表示自动检测) */
25
+ resolution: 0
26
+ },
27
+
28
+ /** 渲染器配置(四期新增 1.2:WebGPU 适配器) */
29
+ renderer: {
30
+ /**
31
+ * 是否优先使用 WebGPU 后端
32
+ * - true: 优先尝试 WebGPU,不支持时根据 webgpu.fallback 决定回退策略
33
+ * - false: 直接使用 WebGL(默认值,保证最大兼容性)
34
+ */
35
+ preferWebGPU: false,
36
+ /** WebGPU 相关子配置 */
37
+ webgpu: {
38
+ /**
39
+ * 不支持 WebGPU 时是否自动回退到 WebGL
40
+ * - true: 自动回退(默认值,保证启动成功)
41
+ * - false: 抛出错误,阻止启动(适用于必须使用 WebGPU 的场景)
42
+ */
43
+ fallback: true
44
+ }
45
+ },
46
+
47
+ /** 核心配置 */
48
+ core: {
49
+ /** 是否启用开发模式(开发模式增强参数校验、状态守卫、内存检测) */
50
+ developmentMode: true
51
+ },
52
+
53
+ /** 模块配置 */
54
+ modules: {
55
+ /** 日志系统配置 */
56
+ logger: {
57
+ /** 日志级别:0=DEBUG, 1=INFO, 2=WARN, 3=ERROR, 4=NONE */
58
+ level: 1
59
+ }
60
+ }
61
+ }
62
+
63
+ export { DefaultConfig }
@@ -0,0 +1,7 @@
1
+ // ============================================================================
2
+ // Nimbus2D - Application 模块统一导出
3
+ // ============================================================================
4
+
5
+ export { Application } from './Application.js'
6
+ export { AppState } from './AppState.js'
7
+ export { DefaultConfig } from './DefaultConfig.js'