@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.
- package/dist/index.mjs +18433 -0
- package/package.json +39 -0
- package/src/base/EventEmitter.js +187 -0
- package/src/base/Subsystem.js +183 -0
- package/src/base/index.js +6 -0
- package/src/core/Application/AppState.js +27 -0
- package/src/core/Application/Application.js +480 -0
- package/src/core/Application/DefaultConfig.js +63 -0
- package/src/core/Application/index.js +7 -0
- package/src/core/AssetManager/AssetManager.js +711 -0
- package/src/core/AssetManager/AssetTypes.js +108 -0
- package/src/core/AssetManager/adapters/IResourceAdapter.js +50 -0
- package/src/core/AssetManager/adapters/PixiAdapter.js +90 -0
- package/src/core/AssetManager/core/RefCounter.js +167 -0
- package/src/core/AssetManager/core/ResourceCache.js +281 -0
- package/src/core/AssetManager/core/ResourceEntry.js +191 -0
- package/src/core/AssetManager/core/ResourceEventBus.js +127 -0
- package/src/core/AssetManager/handlers/IResourceHandler.js +45 -0
- package/src/core/AssetManager/index.js +26 -0
- package/src/core/AssetManager/plugins/IResourcePlugin.js +56 -0
- package/src/core/Camera/Camera.js +534 -0
- package/src/core/Camera/CameraTypes.js +59 -0
- package/src/core/Camera/index.js +13 -0
- package/src/core/ConfigSystem/ConfigLayer.js +230 -0
- package/src/core/ConfigSystem/ConfigLayerType.js +31 -0
- package/src/core/ConfigSystem/ConfigMerger.js +50 -0
- package/src/core/ConfigSystem/ConfigPath.js +96 -0
- package/src/core/ConfigSystem/ConfigSystem.js +378 -0
- package/src/core/ConfigSystem/ConfigTypes.js +29 -0
- package/src/core/ConfigSystem/ConfigWatcher.js +84 -0
- package/src/core/ConfigSystem/index.js +19 -0
- package/src/core/EventBus/EventBus.js +797 -0
- package/src/core/EventBus/Interceptor.js +26 -0
- package/src/core/EventBus/PerformanceStats.js +105 -0
- package/src/core/EventBus/index.js +7 -0
- package/src/core/Lifecycle/Lifecycle.js +265 -0
- package/src/core/Lifecycle/LifecycleState.js +31 -0
- package/src/core/Lifecycle/index.js +6 -0
- package/src/core/Logger/ConsoleHandler.js +55 -0
- package/src/core/Logger/LogHandler.js +34 -0
- package/src/core/Logger/LogLevel.js +38 -0
- package/src/core/Logger/Logger.js +234 -0
- package/src/core/Logger/index.js +8 -0
- package/src/core/PluginSystem/Plugin.js +156 -0
- package/src/core/PluginSystem/PluginEntry.js +102 -0
- package/src/core/PluginSystem/PluginState.js +30 -0
- package/src/core/PluginSystem/PluginSystem.js +530 -0
- package/src/core/PluginSystem/index.js +8 -0
- package/src/core/PoolManager/DefaultConfig.js +19 -0
- package/src/core/PoolManager/ObjectPool.js +326 -0
- package/src/core/PoolManager/PoolManager.js +253 -0
- package/src/core/PoolManager/PoolTypes.js +92 -0
- package/src/core/PoolManager/index.js +15 -0
- package/src/core/SceneManager/FadeTransition.js +64 -0
- package/src/core/SceneManager/MaskTransition.js +234 -0
- package/src/core/SceneManager/Scene.js +221 -0
- package/src/core/SceneManager/SceneManager.js +658 -0
- package/src/core/SceneManager/SceneState.js +29 -0
- package/src/core/SceneManager/SlideTransition.js +113 -0
- package/src/core/SceneManager/Transition.js +102 -0
- package/src/core/SceneManager/ZoomTransition.js +119 -0
- package/src/core/SceneManager/index.js +12 -0
- package/src/core/SpriteGPULayer/SpriteGPULayer.js +321 -0
- package/src/core/SpriteGPULayer/SpriteGPULayerTypes.js +49 -0
- package/src/core/SpriteGPULayer/index.js +11 -0
- package/src/core/Timeline/Clip.js +101 -0
- package/src/core/Timeline/DefaultConfig.js +41 -0
- package/src/core/Timeline/Easing.js +176 -0
- package/src/core/Timeline/Timeline.js +458 -0
- package/src/core/Timeline/TimelineTypes.js +89 -0
- package/src/core/Timeline/Track.js +202 -0
- package/src/core/Timeline/index.js +22 -0
- package/src/errors/ConfigError.js +47 -0
- package/src/errors/LifecycleError.js +58 -0
- package/src/errors/NimbusError.js +43 -0
- package/src/errors/PluginError.js +138 -0
- package/src/errors/ResourceError.js +166 -0
- package/src/errors/SceneError.js +124 -0
- package/src/errors/SubsystemError.js +68 -0
- package/src/errors/index.js +53 -0
- package/src/index.js +86 -0
- package/src/types/index.js +141 -0
- package/src/utils/MemoryChecker.js +374 -0
- package/src/utils/Validator.js +60 -0
- package/src/utils/index.js +84 -0
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
// ============================================================================
|
|
2
|
+
// Nimbus2D - 淡入淡出过渡效果
|
|
3
|
+
// ----------------------------------------------------------------------------
|
|
4
|
+
// 淡出源场景(alpha 1 → 0),淡入目标场景(alpha 0 → 1)。
|
|
5
|
+
//
|
|
6
|
+
// 继承关系:
|
|
7
|
+
// Transition → FadeTransition
|
|
8
|
+
// ============================================================================
|
|
9
|
+
|
|
10
|
+
import { Transition } from './Transition.js'
|
|
11
|
+
|
|
12
|
+
class FadeTransition extends Transition {
|
|
13
|
+
/**
|
|
14
|
+
* 构造函数
|
|
15
|
+
* @param {Object} [options={}] - 选项(继承自 Transition)
|
|
16
|
+
*/
|
|
17
|
+
constructor(options = {}) {
|
|
18
|
+
super(options)
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
/**
|
|
22
|
+
* 执行淡入淡出过渡
|
|
23
|
+
* @param {import('./Scene.js').Scene} fromScene - 源场景
|
|
24
|
+
* @param {import('./Scene.js').Scene} toScene - 目标场景
|
|
25
|
+
* @returns {Promise<void>}
|
|
26
|
+
*/
|
|
27
|
+
async execute(fromScene, toScene) {
|
|
28
|
+
// 触发开始回调
|
|
29
|
+
if (this._onTransitionStart) this._onTransitionStart()
|
|
30
|
+
|
|
31
|
+
// 确保目标场景可见且初始 alpha 为 0
|
|
32
|
+
if (toScene && toScene.stage) {
|
|
33
|
+
toScene.stage.alpha = 0
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
// 阶段1:淡出源场景(半段时间)
|
|
37
|
+
const halfDuration = this._duration / 2
|
|
38
|
+
if (fromScene && fromScene.stage) {
|
|
39
|
+
await this._animate(halfDuration, (progress) => {
|
|
40
|
+
fromScene.stage.alpha = 1 - progress
|
|
41
|
+
})
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
// 阶段2:淡入目标场景(半段时间)
|
|
45
|
+
if (toScene && toScene.stage) {
|
|
46
|
+
await this._animate(halfDuration, (progress) => {
|
|
47
|
+
toScene.stage.alpha = progress
|
|
48
|
+
})
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
// 确保最终状态
|
|
52
|
+
if (fromScene && fromScene.stage) {
|
|
53
|
+
fromScene.stage.alpha = 1
|
|
54
|
+
}
|
|
55
|
+
if (toScene && toScene.stage) {
|
|
56
|
+
toScene.stage.alpha = 1
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
// 触发结束回调
|
|
60
|
+
if (this._onTransitionEnd) this._onTransitionEnd()
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
export { FadeTransition }
|
|
@@ -0,0 +1,234 @@
|
|
|
1
|
+
// ============================================================================
|
|
2
|
+
// Nimbus2D - MaskTransition 遮罩转场效果
|
|
3
|
+
// ----------------------------------------------------------------------------
|
|
4
|
+
// 职责:
|
|
5
|
+
// 1. 实现遮罩转场动画(目标场景按遮罩形状逐渐显示)
|
|
6
|
+
// 2. 支持 circle/rect/diamond 三种内置遮罩形状
|
|
7
|
+
// 3. 支持 customMask 自定义遮罩函数(用户返回 Graphics 绘制逻辑)
|
|
8
|
+
// 4. 复用同一 Graphics 实例避免每帧创建(性能优化)
|
|
9
|
+
// 5. 完成后自动清理 Graphics 资源(避免内存泄漏)
|
|
10
|
+
//
|
|
11
|
+
// 继承关系:
|
|
12
|
+
// Transition → MaskTransition
|
|
13
|
+
//
|
|
14
|
+
// 设计决策:
|
|
15
|
+
// - 继承现有 Transition 基类(execute 契约),复用 _animate/_applyEasing
|
|
16
|
+
// - Graphics 复用:同一实例 clear() 后重绘,避免每帧 GC 压力
|
|
17
|
+
// - 遮罩挂载位置:优先挂载到 toStage.parent(pixi stage),降级到 toStage 本身
|
|
18
|
+
// - 资源清理:execute() 完成后自动销毁 Graphics,destroy() 提供强制清理入口
|
|
19
|
+
// - 视口尺寸获取:从 toStage.parent 降级到 800x600 默认值
|
|
20
|
+
//
|
|
21
|
+
// 四期新增(任务 1.5/3.1):对标 Phaser 的 MaskTransition
|
|
22
|
+
// ============================================================================
|
|
23
|
+
|
|
24
|
+
import { Graphics } from 'pixi.js'
|
|
25
|
+
import { Transition } from './Transition.js'
|
|
26
|
+
|
|
27
|
+
class MaskTransition extends Transition {
|
|
28
|
+
/**
|
|
29
|
+
* 构造函数
|
|
30
|
+
* @param {Object} [options={}] - 选项(继承自 Transition)
|
|
31
|
+
* @param {string} [options.maskShape='circle'] - 遮罩形状(circle/rect/diamond)
|
|
32
|
+
* @param {Function} [options.customMask] - 自定义遮罩函数 (graphics, progress, viewWidth, viewHeight) => void
|
|
33
|
+
* 用户提供自定义绘制逻辑时,maskShape 参数被忽略
|
|
34
|
+
*/
|
|
35
|
+
constructor(options = {}) {
|
|
36
|
+
super(options)
|
|
37
|
+
|
|
38
|
+
/** @type {string} 遮罩形状(circle/rect/diamond) */
|
|
39
|
+
this._maskShape = options.maskShape ?? 'circle'
|
|
40
|
+
|
|
41
|
+
/**
|
|
42
|
+
* 自定义遮罩函数
|
|
43
|
+
* 签名:(graphics, progress, viewWidth, viewHeight) => void
|
|
44
|
+
* 用户负责在函数内调用 graphics.clear() 并绘制遮罩形状
|
|
45
|
+
* @type {Function|null}
|
|
46
|
+
*/
|
|
47
|
+
this._customMask = options.customMask ?? null
|
|
48
|
+
|
|
49
|
+
/**
|
|
50
|
+
* 复用的 Graphics 实例
|
|
51
|
+
* 整个转场过程复用同一实例,避免每帧创建销毁
|
|
52
|
+
* @type {Graphics|null}
|
|
53
|
+
* @private
|
|
54
|
+
*/
|
|
55
|
+
this._maskGraphics = new Graphics()
|
|
56
|
+
|
|
57
|
+
/** @type {boolean} Graphics 是否已销毁(防重复销毁) */
|
|
58
|
+
this._graphicsDestroyed = false
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
/**
|
|
62
|
+
* 执行遮罩转场
|
|
63
|
+
* @param {import('./Scene.js').Scene} fromScene - 源场景
|
|
64
|
+
* @param {import('./Scene.js').Scene} toScene - 目标场景
|
|
65
|
+
* @returns {Promise<void>}
|
|
66
|
+
*/
|
|
67
|
+
async execute(fromScene, toScene) {
|
|
68
|
+
// 触发开始回调
|
|
69
|
+
if (this._onTransitionStart) this._onTransitionStart()
|
|
70
|
+
|
|
71
|
+
/** @type {import('pixi.js').Container|null} 目标场景 stage */
|
|
72
|
+
const toStage = toScene ? toScene.stage : null
|
|
73
|
+
/** @type {import('pixi.js').Container|null} 源场景 stage */
|
|
74
|
+
const fromStage = fromScene ? fromScene.stage : null
|
|
75
|
+
|
|
76
|
+
// 无目标场景时直接结束(无法应用遮罩)
|
|
77
|
+
if (!toStage) {
|
|
78
|
+
if (this._onTransitionEnd) this._onTransitionEnd()
|
|
79
|
+
return
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
// 获取视口尺寸(从 toStage.parent 降级到默认值 800x600)
|
|
83
|
+
const viewWidth = (toStage.parent && toStage.parent.width) ? toStage.parent.width : 800
|
|
84
|
+
const viewHeight = (toStage.parent && toStage.parent.height) ? toStage.parent.height : 600
|
|
85
|
+
|
|
86
|
+
// 将 Graphics 添加到显示列表(PIXI v8 要求 mask 必须在显示列表中)
|
|
87
|
+
// 优先添加到 toStage.parent(与 toStage 同级),降级到 toStage 本身
|
|
88
|
+
/** @type {import('pixi.js').Container} Graphics 挂载容器 */
|
|
89
|
+
const maskParent = toStage.parent || toStage
|
|
90
|
+
maskParent.addChild(this._maskGraphics)
|
|
91
|
+
|
|
92
|
+
// 应用遮罩到目标场景
|
|
93
|
+
toStage.mask = this._maskGraphics
|
|
94
|
+
|
|
95
|
+
try {
|
|
96
|
+
// 执行遮罩动画
|
|
97
|
+
await this._animate(this._duration, (progress) => {
|
|
98
|
+
// 绘制遮罩(每帧重绘)
|
|
99
|
+
this._drawMask(progress, viewWidth, viewHeight)
|
|
100
|
+
// 源场景同步淡出(增强转场视觉效果)
|
|
101
|
+
if (fromStage) {
|
|
102
|
+
fromStage.alpha = 1 - progress
|
|
103
|
+
}
|
|
104
|
+
})
|
|
105
|
+
} finally {
|
|
106
|
+
// 无论动画成功或失败,都清理遮罩资源并恢复源场景 alpha
|
|
107
|
+
// 避免异常情况下 fromStage.alpha 残留为 0 导致场景不可见
|
|
108
|
+
this._cleanupMask(toStage)
|
|
109
|
+
if (fromStage) {
|
|
110
|
+
fromStage.alpha = 1
|
|
111
|
+
}
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
// 触发结束回调
|
|
115
|
+
if (this._onTransitionEnd) this._onTransitionEnd()
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
// --------------------------------------------------------------------------
|
|
119
|
+
// 私有方法:遮罩绘制
|
|
120
|
+
// --------------------------------------------------------------------------
|
|
121
|
+
|
|
122
|
+
/**
|
|
123
|
+
* 绘制遮罩(清空并重绘复用的 Graphics)
|
|
124
|
+
* @param {number} progress - 进度 0→1
|
|
125
|
+
* @param {number} viewWidth - 视口宽度
|
|
126
|
+
* @param {number} viewHeight - 视口高度
|
|
127
|
+
* @private
|
|
128
|
+
*/
|
|
129
|
+
_drawMask(progress, viewWidth, viewHeight) {
|
|
130
|
+
// 自定义遮罩优先
|
|
131
|
+
if (typeof this._customMask === 'function') {
|
|
132
|
+
try {
|
|
133
|
+
this._customMask(this._maskGraphics, progress, viewWidth, viewHeight)
|
|
134
|
+
} catch (e) {
|
|
135
|
+
// 自定义遮罩异常时降级到 circle
|
|
136
|
+
this._drawBuiltinMask(progress, viewWidth, viewHeight)
|
|
137
|
+
}
|
|
138
|
+
return
|
|
139
|
+
}
|
|
140
|
+
|
|
141
|
+
this._drawBuiltinMask(progress, viewWidth, viewHeight)
|
|
142
|
+
}
|
|
143
|
+
|
|
144
|
+
/**
|
|
145
|
+
* 绘制内置遮罩(circle/rect/diamond)
|
|
146
|
+
* @param {number} progress - 进度 0→1
|
|
147
|
+
* @param {number} viewWidth - 视口宽度
|
|
148
|
+
* @param {number} viewHeight - 视口高度
|
|
149
|
+
* @private
|
|
150
|
+
*/
|
|
151
|
+
_drawBuiltinMask(progress, viewWidth, viewHeight) {
|
|
152
|
+
this._maskGraphics.clear()
|
|
153
|
+
|
|
154
|
+
// 遮罩尺寸:取视口对角线长度乘以 progress,确保完全覆盖
|
|
155
|
+
/** @type {number} 对角线长度(保证任意形状都能覆盖整个视口) */
|
|
156
|
+
const maxSize = Math.sqrt(viewWidth * viewWidth + viewHeight * viewHeight) * progress
|
|
157
|
+
/** @type {number} 中心 X */
|
|
158
|
+
const cx = viewWidth / 2
|
|
159
|
+
/** @type {number} 中心 Y */
|
|
160
|
+
const cy = viewHeight / 2
|
|
161
|
+
|
|
162
|
+
switch (this._maskShape) {
|
|
163
|
+
case 'circle':
|
|
164
|
+
// 圆形遮罩:从中心向外扩展
|
|
165
|
+
this._maskGraphics.circle(cx, cy, maxSize / 2)
|
|
166
|
+
break
|
|
167
|
+
case 'rect':
|
|
168
|
+
// 矩形遮罩:从中心向外扩展
|
|
169
|
+
this._maskGraphics.rect(
|
|
170
|
+
cx - maxSize / 2,
|
|
171
|
+
cy - maxSize / 2,
|
|
172
|
+
maxSize,
|
|
173
|
+
maxSize
|
|
174
|
+
)
|
|
175
|
+
break
|
|
176
|
+
case 'diamond':
|
|
177
|
+
// 菱形遮罩:从中心向外扩展
|
|
178
|
+
this._maskGraphics.moveTo(cx, cy - maxSize / 2)
|
|
179
|
+
this._maskGraphics.lineTo(cx + maxSize / 2, cy)
|
|
180
|
+
this._maskGraphics.lineTo(cx, cy + maxSize / 2)
|
|
181
|
+
this._maskGraphics.lineTo(cx - maxSize / 2, cy)
|
|
182
|
+
this._maskGraphics.closePath()
|
|
183
|
+
break
|
|
184
|
+
default:
|
|
185
|
+
// 未知形状降级到 circle
|
|
186
|
+
this._maskGraphics.circle(cx, cy, maxSize / 2)
|
|
187
|
+
break
|
|
188
|
+
}
|
|
189
|
+
|
|
190
|
+
// 填充白色(mask 只关心 alpha 通道,颜色不影响)
|
|
191
|
+
this._maskGraphics.fill(0xFFFFFF)
|
|
192
|
+
}
|
|
193
|
+
|
|
194
|
+
/**
|
|
195
|
+
* 清理遮罩资源
|
|
196
|
+
* 移除 mask 引用 + 从父容器移除 Graphics + 销毁 Graphics
|
|
197
|
+
* @param {import('pixi.js').Container|null} toStage - 目标场景 stage
|
|
198
|
+
* @private
|
|
199
|
+
*/
|
|
200
|
+
_cleanupMask(toStage) {
|
|
201
|
+
// 移除 mask 引用(避免引用悬挂)
|
|
202
|
+
if (toStage) {
|
|
203
|
+
toStage.mask = null
|
|
204
|
+
}
|
|
205
|
+
|
|
206
|
+
// 从父容器移除 Graphics 并销毁
|
|
207
|
+
if (this._maskGraphics && !this._graphicsDestroyed) {
|
|
208
|
+
if (this._maskGraphics.parent) {
|
|
209
|
+
this._maskGraphics.parent.removeChild(this._maskGraphics)
|
|
210
|
+
}
|
|
211
|
+
try {
|
|
212
|
+
this._maskGraphics.destroy()
|
|
213
|
+
} catch (e) {
|
|
214
|
+
// 销毁异常忽略
|
|
215
|
+
}
|
|
216
|
+
this._maskGraphics = null
|
|
217
|
+
this._graphicsDestroyed = true
|
|
218
|
+
}
|
|
219
|
+
}
|
|
220
|
+
|
|
221
|
+
// --------------------------------------------------------------------------
|
|
222
|
+
// 销毁
|
|
223
|
+
// --------------------------------------------------------------------------
|
|
224
|
+
|
|
225
|
+
/**
|
|
226
|
+
* 销毁遮罩转场(强制清理 Graphics 资源)
|
|
227
|
+
* 正常流程下 execute() 完成后会自动清理,此方法用于异常情况下强制清理
|
|
228
|
+
*/
|
|
229
|
+
destroy() {
|
|
230
|
+
this._cleanupMask(null)
|
|
231
|
+
}
|
|
232
|
+
}
|
|
233
|
+
|
|
234
|
+
export { MaskTransition }
|
|
@@ -0,0 +1,221 @@
|
|
|
1
|
+
// ============================================================================
|
|
2
|
+
// Nimbus2D - 场景基类
|
|
3
|
+
// ----------------------------------------------------------------------------
|
|
4
|
+
// 所有游戏场景必须继承此基类,提供场景级事件能力和生命周期钩子。
|
|
5
|
+
//
|
|
6
|
+
// 设计决策:
|
|
7
|
+
// - 继承 EventEmitter,提供场景级事件能力
|
|
8
|
+
// - 构造函数创建 Container(从 pixi.js 导入)作为 stage
|
|
9
|
+
// - _state 由 SceneManager 设置(构造函数不设置,见决策 106)
|
|
10
|
+
// - _assetManager 由 SceneManager 注入(通过 _setAssetManager)
|
|
11
|
+
// - 内置资源引用管理(_retainAsset + _releaseAssets)
|
|
12
|
+
// - 5 个生命周期钩子:onCreate/onStart/onStop/onPause/onResume
|
|
13
|
+
// - 无 onDestroy 方法(资源引用由 destroy 自动释放)
|
|
14
|
+
// ============================================================================
|
|
15
|
+
|
|
16
|
+
import { Container } from 'pixi.js'
|
|
17
|
+
import { EventEmitter } from '../../base/EventEmitter.js'
|
|
18
|
+
import { SceneState } from './SceneState.js'
|
|
19
|
+
import { SceneError } from '../../errors/SceneError.js'
|
|
20
|
+
|
|
21
|
+
class Scene extends EventEmitter {
|
|
22
|
+
/**
|
|
23
|
+
* 构造函数
|
|
24
|
+
* @param {string} name - 场景名称
|
|
25
|
+
*/
|
|
26
|
+
constructor(name) {
|
|
27
|
+
super()
|
|
28
|
+
|
|
29
|
+
/** @type {string} 场景名称 */
|
|
30
|
+
this._name = name
|
|
31
|
+
|
|
32
|
+
/** @type {import('pixi.js').Container} 场景舞台(构造函数中创建) */
|
|
33
|
+
this._stage = new Container()
|
|
34
|
+
|
|
35
|
+
/** @type {SceneState|null} 场景状态(由 SceneManager 设置,构造函数不设置) */
|
|
36
|
+
this._state = null
|
|
37
|
+
|
|
38
|
+
/** @type {boolean} 是否可见 */
|
|
39
|
+
this._isVisible = true
|
|
40
|
+
|
|
41
|
+
/** @type {number} 层级 */
|
|
42
|
+
this._zIndex = 0
|
|
43
|
+
|
|
44
|
+
/** @type {import('../AssetManager/AssetManager.js').AssetManager|null} 资源管理器(由 SceneManager 注入) */
|
|
45
|
+
this._assetManager = null
|
|
46
|
+
|
|
47
|
+
/** @type {Set<string>} 已引用的资源 ID 集合 */
|
|
48
|
+
this._retainedAssets = new Set()
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
// --------------------------------------------------------------------------
|
|
52
|
+
// 属性
|
|
53
|
+
// --------------------------------------------------------------------------
|
|
54
|
+
|
|
55
|
+
/** @type {string} 场景名称 */
|
|
56
|
+
get name() { return this._name }
|
|
57
|
+
|
|
58
|
+
/** @type {SceneState|null} 场景状态 */
|
|
59
|
+
get state() { return this._state }
|
|
60
|
+
|
|
61
|
+
/** @type {import('pixi.js').Container} 场景舞台 */
|
|
62
|
+
get stage() { return this._stage }
|
|
63
|
+
|
|
64
|
+
/** @type {boolean} 是否可见 */
|
|
65
|
+
get isVisible() { return this._isVisible }
|
|
66
|
+
|
|
67
|
+
/** @type {number} 层级 */
|
|
68
|
+
get zIndex() { return this._zIndex }
|
|
69
|
+
|
|
70
|
+
// --------------------------------------------------------------------------
|
|
71
|
+
// 生命周期钩子(子类重写)
|
|
72
|
+
// --------------------------------------------------------------------------
|
|
73
|
+
|
|
74
|
+
/**
|
|
75
|
+
* 创建时调用(仅一次,首次 start 时调用)
|
|
76
|
+
* @returns {Promise<void>|void}
|
|
77
|
+
*/
|
|
78
|
+
async onCreate() {
|
|
79
|
+
// 基类空实现,子类按需重写
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
/**
|
|
83
|
+
* 启动时调用(每次 start)
|
|
84
|
+
* @returns {Promise<void>|void}
|
|
85
|
+
*/
|
|
86
|
+
async onStart() {
|
|
87
|
+
// 基类空实现,子类按需重写
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
/**
|
|
91
|
+
* 停止时调用(每次 stop)
|
|
92
|
+
* @returns {Promise<void>|void}
|
|
93
|
+
*/
|
|
94
|
+
async onStop() {
|
|
95
|
+
// 基类空实现,子类按需重写
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
/**
|
|
99
|
+
* 暂停时调用
|
|
100
|
+
* @returns {void}
|
|
101
|
+
*/
|
|
102
|
+
onPause() {
|
|
103
|
+
// 基类空实现,子类按需重写
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
/**
|
|
107
|
+
* 恢复时调用
|
|
108
|
+
* @returns {void}
|
|
109
|
+
*/
|
|
110
|
+
onResume() {
|
|
111
|
+
// 基类空实现,子类按需重写
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
// --------------------------------------------------------------------------
|
|
115
|
+
// 更新方法(子类重写)
|
|
116
|
+
// --------------------------------------------------------------------------
|
|
117
|
+
|
|
118
|
+
/**
|
|
119
|
+
* 每帧更新
|
|
120
|
+
* @param {number} delta - 帧间隔(秒)
|
|
121
|
+
*/
|
|
122
|
+
update(delta) {
|
|
123
|
+
// 基类空实现,子类按需重写
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
// --------------------------------------------------------------------------
|
|
127
|
+
// 资源引用管理
|
|
128
|
+
// --------------------------------------------------------------------------
|
|
129
|
+
|
|
130
|
+
/**
|
|
131
|
+
* 引用资源(异步)
|
|
132
|
+
* @param {string} assetId - 资源 ID
|
|
133
|
+
* @returns {Promise<boolean>} - 是否引用成功
|
|
134
|
+
*/
|
|
135
|
+
async _retainAsset(assetId) {
|
|
136
|
+
// 已引用过则直接返回
|
|
137
|
+
if (this._retainedAssets.has(assetId)) return true
|
|
138
|
+
|
|
139
|
+
// AssetManager 必须先注入
|
|
140
|
+
if (!this._assetManager) {
|
|
141
|
+
throw new SceneError(`Scene ${this._name} 未注入 AssetManager,请通过 SceneManager.register 注册场景`)
|
|
142
|
+
}
|
|
143
|
+
|
|
144
|
+
const data = await this._assetManager.retain(assetId, this._name)
|
|
145
|
+
|
|
146
|
+
// 使用 !== undefined && !== null 判断成功,避免 falsy 值误判
|
|
147
|
+
const ok = data !== undefined && data !== null
|
|
148
|
+
if (ok) {
|
|
149
|
+
this._retainedAssets.add(assetId)
|
|
150
|
+
}
|
|
151
|
+
return ok
|
|
152
|
+
}
|
|
153
|
+
|
|
154
|
+
/**
|
|
155
|
+
* 释放所有引用的资源(由 destroy 自动调用)
|
|
156
|
+
*/
|
|
157
|
+
_releaseAssets() {
|
|
158
|
+
if (!this._assetManager) return
|
|
159
|
+
for (const assetId of this._retainedAssets) {
|
|
160
|
+
try {
|
|
161
|
+
this._assetManager.release(assetId, this._name)
|
|
162
|
+
} catch (e) {
|
|
163
|
+
// 忽略释放错误
|
|
164
|
+
}
|
|
165
|
+
}
|
|
166
|
+
this._retainedAssets.clear()
|
|
167
|
+
}
|
|
168
|
+
|
|
169
|
+
// --------------------------------------------------------------------------
|
|
170
|
+
// 内部方法(由 SceneManager 调用)
|
|
171
|
+
// --------------------------------------------------------------------------
|
|
172
|
+
|
|
173
|
+
/**
|
|
174
|
+
* 注入 AssetManager 引用(由 SceneManager.register 时调用)
|
|
175
|
+
* @param {import('../AssetManager/AssetManager.js').AssetManager} assetManager - 资源管理器实例
|
|
176
|
+
* @private
|
|
177
|
+
*/
|
|
178
|
+
_setAssetManager(assetManager) {
|
|
179
|
+
this._assetManager = assetManager
|
|
180
|
+
}
|
|
181
|
+
|
|
182
|
+
/**
|
|
183
|
+
* 设置场景状态(由 SceneManager 调用)
|
|
184
|
+
* @param {SceneState} state - 新状态
|
|
185
|
+
* @private
|
|
186
|
+
*/
|
|
187
|
+
_setState(state) {
|
|
188
|
+
this._state = state
|
|
189
|
+
}
|
|
190
|
+
|
|
191
|
+
// --------------------------------------------------------------------------
|
|
192
|
+
// 销毁
|
|
193
|
+
// --------------------------------------------------------------------------
|
|
194
|
+
|
|
195
|
+
/**
|
|
196
|
+
* 销毁场景(自动释放资源引用 + 销毁 stage)
|
|
197
|
+
* @returns {Promise<void>}
|
|
198
|
+
*/
|
|
199
|
+
async destroy() {
|
|
200
|
+
// 释放所有资源引用
|
|
201
|
+
this._releaseAssets()
|
|
202
|
+
|
|
203
|
+
// 销毁场景舞台 Container
|
|
204
|
+
if (this._stage) {
|
|
205
|
+
this._stage.destroy({ children: true })
|
|
206
|
+
this._stage = null
|
|
207
|
+
}
|
|
208
|
+
|
|
209
|
+
this._state = SceneState.DESTROYED
|
|
210
|
+
this._assetManager = null
|
|
211
|
+
this._retainedAssets.clear()
|
|
212
|
+
|
|
213
|
+
// 先 emit destroyed 事件(super.destroy 后 emit 无效)
|
|
214
|
+
this.emit('destroyed', { name: this._name })
|
|
215
|
+
|
|
216
|
+
// 调用父类 destroy 设置 _destroyed = true 并清理监听器
|
|
217
|
+
super.destroy()
|
|
218
|
+
}
|
|
219
|
+
}
|
|
220
|
+
|
|
221
|
+
export { Scene }
|