kiwiengine 0.7.0 → 1.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/lib/asset/audio.js +25 -7
- package/lib/asset/audio.js.map +1 -1
- package/lib/dom/dom-particle.js +23 -74
- package/lib/dom/dom-particle.js.map +1 -1
- package/lib/node/core/game-object.js +1 -4
- package/lib/node/core/game-object.js.map +1 -1
- package/lib/node/core/renderable.js +6 -4
- package/lib/node/core/renderable.js.map +1 -1
- package/lib/node/core/transformable.js +11 -42
- package/lib/node/core/transformable.js.map +1 -1
- package/lib/node/ext/animated-sprite.js +1 -8
- package/lib/node/ext/animated-sprite.js.map +1 -1
- package/lib/node/ext/bitmap-text.js +4 -61
- package/lib/node/ext/bitmap-text.js.map +1 -1
- package/lib/node/ext/circle.js +1 -2
- package/lib/node/ext/circle.js.map +1 -1
- package/lib/node/ext/particle.js +15 -65
- package/lib/node/ext/particle.js.map +1 -1
- package/lib/node/ext/rectangle.js +1 -2
- package/lib/node/ext/rectangle.js.map +1 -1
- package/lib/renderer/camera.js +0 -8
- package/lib/renderer/camera.js.map +1 -1
- package/lib/renderer/renderer.js +2 -7
- package/lib/renderer/renderer.js.map +1 -1
- package/lib/types/asset/audio.d.ts +8 -0
- package/lib/types/asset/audio.d.ts.map +1 -1
- package/lib/types/dom/dom-particle.d.ts +0 -1
- package/lib/types/dom/dom-particle.d.ts.map +1 -1
- package/lib/types/node/core/game-object.d.ts +1 -3
- package/lib/types/node/core/game-object.d.ts.map +1 -1
- package/lib/types/node/core/renderable.d.ts +1 -0
- package/lib/types/node/core/renderable.d.ts.map +1 -1
- package/lib/types/node/core/transformable.d.ts.map +1 -1
- package/lib/types/node/ext/animated-sprite.d.ts.map +1 -1
- package/lib/types/node/ext/bitmap-text.d.ts.map +1 -1
- package/lib/types/node/ext/circle.d.ts.map +1 -1
- package/lib/types/node/ext/particle.d.ts +0 -1
- package/lib/types/node/ext/particle.d.ts.map +1 -1
- package/lib/types/node/ext/rectangle.d.ts.map +1 -1
- package/lib/types/renderer/camera.d.ts.map +1 -1
- package/lib/types/renderer/renderer.d.ts.map +1 -1
- package/package.json +1 -1
- package/src/asset/audio.ts +28 -7
- package/src/dom/dom-particle.ts +24 -91
- package/src/node/core/game-object.ts +2 -10
- package/src/node/core/renderable.ts +5 -4
- package/src/node/core/transformable.ts +11 -49
- package/src/node/ext/animated-sprite.ts +1 -10
- package/src/node/ext/bitmap-text.ts +4 -70
- package/src/node/ext/circle.ts +1 -2
- package/src/node/ext/particle.ts +16 -80
- package/src/node/ext/rectangle.ts +1 -2
- package/src/renderer/camera.ts +0 -6
- package/src/renderer/renderer.ts +2 -9
package/src/node/ext/particle.ts
CHANGED
|
@@ -18,18 +18,11 @@ export type ParticleSystemOptions = {
|
|
|
18
18
|
orientToVelocity: boolean
|
|
19
19
|
|
|
20
20
|
blendMode?: BLEND_MODES // ex) 'screen', 'multiply'
|
|
21
|
-
|
|
22
|
-
// [성능 최적화] 오브젝트 풀 크기 설정 (기본값: 100)
|
|
23
|
-
// 풀 크기를 늘리면 메모리를 더 사용하지만 GC 스파이크를 줄일 수 있음
|
|
24
|
-
poolSize?: number
|
|
25
21
|
} & GameObjectOptions
|
|
26
22
|
|
|
27
23
|
interface Particle {
|
|
28
24
|
sprite: PixiSprite
|
|
29
25
|
|
|
30
|
-
// [성능 최적화] 활성 상태 플래그 - 풀링에서 재사용 여부 판단
|
|
31
|
-
active: boolean
|
|
32
|
-
|
|
33
26
|
age: number
|
|
34
27
|
lifespan: number
|
|
35
28
|
|
|
@@ -59,10 +52,6 @@ export class ParticleSystem extends GameObject {
|
|
|
59
52
|
#loadTexturePromise: Promise<void>
|
|
60
53
|
#particles: Particle[] = []
|
|
61
54
|
|
|
62
|
-
// [성능 최적화] 오브젝트 풀 - 스프라이트 재사용으로 GC 부담 감소
|
|
63
|
-
#spritePool: PixiSprite[] = []
|
|
64
|
-
#poolSize: number
|
|
65
|
-
|
|
66
55
|
constructor(options: ParticleSystemOptions) {
|
|
67
56
|
super(options)
|
|
68
57
|
|
|
@@ -76,7 +65,6 @@ export class ParticleSystem extends GameObject {
|
|
|
76
65
|
this.#fadeRate = options.fadeRate
|
|
77
66
|
this.#orientToVelocity = options.orientToVelocity
|
|
78
67
|
this.#blendMode = options.blendMode
|
|
79
|
-
this.#poolSize = options.poolSize ?? 100
|
|
80
68
|
|
|
81
69
|
this.#loadTexturePromise = this.#loadTexture()
|
|
82
70
|
}
|
|
@@ -90,46 +78,6 @@ export class ParticleSystem extends GameObject {
|
|
|
90
78
|
}
|
|
91
79
|
}
|
|
92
80
|
|
|
93
|
-
// [성능 최적화] 풀에서 스프라이트 가져오거나 새로 생성
|
|
94
|
-
#acquireSprite(x: number, y: number, scale: number, angle: number): PixiSprite {
|
|
95
|
-
let sprite = this.#spritePool.pop()
|
|
96
|
-
|
|
97
|
-
if (sprite) {
|
|
98
|
-
// 풀에서 가져온 스프라이트 재설정
|
|
99
|
-
sprite.x = x
|
|
100
|
-
sprite.y = y
|
|
101
|
-
sprite.scale.set(scale, scale)
|
|
102
|
-
sprite.alpha = this.#startAlpha ?? 1
|
|
103
|
-
sprite.rotation = this.#orientToVelocity ? angle : 0
|
|
104
|
-
sprite.visible = true
|
|
105
|
-
} else {
|
|
106
|
-
// 풀이 비어있으면 새로 생성
|
|
107
|
-
sprite = new PixiSprite({
|
|
108
|
-
x, y,
|
|
109
|
-
texture: this.#texture,
|
|
110
|
-
anchor: { x: 0.5, y: 0.5 },
|
|
111
|
-
scale: { x: scale, y: scale },
|
|
112
|
-
alpha: this.#startAlpha,
|
|
113
|
-
blendMode: this.#blendMode,
|
|
114
|
-
rotation: this.#orientToVelocity ? angle : undefined,
|
|
115
|
-
})
|
|
116
|
-
this._pixiContainer.addChild(sprite)
|
|
117
|
-
}
|
|
118
|
-
|
|
119
|
-
return sprite
|
|
120
|
-
}
|
|
121
|
-
|
|
122
|
-
// [성능 최적화] 스프라이트를 풀로 반환 (destroy 대신)
|
|
123
|
-
#releaseSprite(sprite: PixiSprite) {
|
|
124
|
-
if (this.#spritePool.length < this.#poolSize) {
|
|
125
|
-
sprite.visible = false
|
|
126
|
-
this.#spritePool.push(sprite)
|
|
127
|
-
} else {
|
|
128
|
-
// 풀이 가득 차면 destroy
|
|
129
|
-
sprite.destroy()
|
|
130
|
-
}
|
|
131
|
-
}
|
|
132
|
-
|
|
133
81
|
async burst({ x, y }: { x: number; y: number }) {
|
|
134
82
|
if (!this.#texture) await this.#loadTexturePromise
|
|
135
83
|
|
|
@@ -142,17 +90,26 @@ export class ParticleSystem extends GameObject {
|
|
|
142
90
|
const velocity = random(this.#velocity.min, this.#velocity.max)
|
|
143
91
|
const scale = random(this.#scale.min, this.#scale.max)
|
|
144
92
|
|
|
145
|
-
const sprite =
|
|
93
|
+
const sprite = new PixiSprite({
|
|
94
|
+
x, y,
|
|
95
|
+
texture: this.#texture,
|
|
96
|
+
anchor: { x: 0.5, y: 0.5 },
|
|
97
|
+
scale: { x: scale, y: scale },
|
|
98
|
+
alpha: this.#startAlpha,
|
|
99
|
+
blendMode: this.#blendMode,
|
|
100
|
+
rotation: this.#orientToVelocity ? angle : undefined,
|
|
101
|
+
})
|
|
146
102
|
|
|
147
103
|
this.#particles.push({
|
|
148
104
|
sprite,
|
|
149
|
-
active: true,
|
|
150
105
|
age: 0,
|
|
151
106
|
lifespan,
|
|
152
107
|
velocityX: velocity * cos,
|
|
153
108
|
velocityY: velocity * sin,
|
|
154
109
|
fadeRate: this.#fadeRate,
|
|
155
110
|
})
|
|
111
|
+
|
|
112
|
+
this._pixiContainer.addChild(sprite)
|
|
156
113
|
}
|
|
157
114
|
}
|
|
158
115
|
|
|
@@ -160,46 +117,25 @@ export class ParticleSystem extends GameObject {
|
|
|
160
117
|
super.update(dt)
|
|
161
118
|
|
|
162
119
|
const ps = this.#particles
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
// 기존: splice(i, 1)은 배열 요소를 이동시켜 O(n) 비용 발생
|
|
166
|
-
// 개선: 마지막 요소와 교체 후 pop()으로 O(1) 제거
|
|
167
|
-
let writeIdx = 0
|
|
168
|
-
for (let readIdx = 0; readIdx < ps.length; readIdx++) {
|
|
169
|
-
const p = ps[readIdx]
|
|
120
|
+
for (let i = 0; i < ps.length; i++) {
|
|
121
|
+
const p = ps[i]
|
|
170
122
|
const g = p.sprite
|
|
171
123
|
|
|
172
124
|
p.age += dt
|
|
173
|
-
|
|
174
125
|
if (p.age > p.lifespan) {
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
126
|
+
g.destroy({ children: true })
|
|
127
|
+
ps.splice(i, 1)
|
|
128
|
+
i--
|
|
178
129
|
continue
|
|
179
130
|
}
|
|
180
131
|
|
|
181
132
|
g.x += p.velocityX * dt
|
|
182
133
|
g.y += p.velocityY * dt
|
|
183
134
|
g.alpha += p.fadeRate * dt
|
|
184
|
-
|
|
185
|
-
// 활성 파티클을 앞으로 이동
|
|
186
|
-
if (writeIdx !== readIdx) {
|
|
187
|
-
ps[writeIdx] = p
|
|
188
|
-
}
|
|
189
|
-
writeIdx++
|
|
190
135
|
}
|
|
191
|
-
|
|
192
|
-
// 비활성 파티클 제거 (한 번에 배열 크기 조정)
|
|
193
|
-
ps.length = writeIdx
|
|
194
136
|
}
|
|
195
137
|
|
|
196
138
|
override remove() {
|
|
197
|
-
// 풀에 있는 스프라이트도 정리
|
|
198
|
-
for (const sprite of this.#spritePool) {
|
|
199
|
-
sprite.destroy()
|
|
200
|
-
}
|
|
201
|
-
this.#spritePool.length = 0
|
|
202
|
-
|
|
203
139
|
textureLoader.release(this.#textureSrc)
|
|
204
140
|
super.remove()
|
|
205
141
|
}
|
|
@@ -16,8 +16,7 @@ export class RectangleNode extends TransformableNode<Graphics, EventMap> {
|
|
|
16
16
|
#stroke?: StrokeInput
|
|
17
17
|
|
|
18
18
|
constructor(options: RectangleNodeOptions) {
|
|
19
|
-
|
|
20
|
-
super(new Graphics(), options)
|
|
19
|
+
super(new Graphics({ sortableChildren: true }), options)
|
|
21
20
|
|
|
22
21
|
this.#width = options.width
|
|
23
22
|
this.#height = options.height
|
package/src/renderer/camera.ts
CHANGED
|
@@ -13,18 +13,12 @@ export class Camera extends EventEmitter<{
|
|
|
13
13
|
get scale() { return this.#scale }
|
|
14
14
|
|
|
15
15
|
setPosition(x: number, y: number) {
|
|
16
|
-
// [성능 최적화] 값이 변경된 경우에만 이벤트 emit
|
|
17
|
-
// 기존: 매번 positionChanged 이벤트 발생 → 불필요한 월드 트랜스폼 업데이트
|
|
18
|
-
// 개선: 값 비교 후 변경 시에만 emit
|
|
19
|
-
if (this.#x === x && this.#y === y) return
|
|
20
16
|
this.#x = x
|
|
21
17
|
this.#y = y
|
|
22
18
|
this.emit('positionChanged')
|
|
23
19
|
}
|
|
24
20
|
|
|
25
21
|
setScale(scale: number) {
|
|
26
|
-
// [성능 최적화] 값이 변경된 경우에만 이벤트 emit
|
|
27
|
-
if (this.#scale === scale) return
|
|
28
22
|
this.#scale = scale
|
|
29
23
|
this.emit('scaleChanged')
|
|
30
24
|
}
|
package/src/renderer/renderer.ts
CHANGED
|
@@ -162,18 +162,11 @@ export class Renderer extends RenderableNode<PixiContainer, {
|
|
|
162
162
|
}
|
|
163
163
|
|
|
164
164
|
#render(dt: number) {
|
|
165
|
-
// [성능 최적화] 렌더러가 준비되지 않은 경우 불필요한 업데이트 스킵
|
|
166
|
-
if (!this.#pixiRenderer) return
|
|
167
|
-
|
|
168
165
|
const scaledDt = dt * this.timeScale
|
|
169
166
|
this.update(scaledDt)
|
|
170
|
-
|
|
171
|
-
// [성능 최적화] 2-pass → 1-pass로 통합
|
|
172
|
-
// 기존: _updateWorldTransform() + _resetWorldTransformDirty() 별도 호출
|
|
173
|
-
// 개선: _updateWorldTransform() 내부에서 dirty 리셋까지 처리
|
|
174
167
|
this._updateWorldTransform()
|
|
175
|
-
|
|
176
|
-
this.#pixiRenderer
|
|
168
|
+
this._resetWorldTransformDirty()
|
|
169
|
+
this.#pixiRenderer?.render(this._pixiContainer)
|
|
177
170
|
this.fpsDisplay?.update()
|
|
178
171
|
|
|
179
172
|
this._isSizeDirty = false
|