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.
Files changed (54) hide show
  1. package/lib/asset/audio.js +25 -7
  2. package/lib/asset/audio.js.map +1 -1
  3. package/lib/dom/dom-particle.js +23 -74
  4. package/lib/dom/dom-particle.js.map +1 -1
  5. package/lib/node/core/game-object.js +1 -4
  6. package/lib/node/core/game-object.js.map +1 -1
  7. package/lib/node/core/renderable.js +6 -4
  8. package/lib/node/core/renderable.js.map +1 -1
  9. package/lib/node/core/transformable.js +11 -42
  10. package/lib/node/core/transformable.js.map +1 -1
  11. package/lib/node/ext/animated-sprite.js +1 -8
  12. package/lib/node/ext/animated-sprite.js.map +1 -1
  13. package/lib/node/ext/bitmap-text.js +4 -61
  14. package/lib/node/ext/bitmap-text.js.map +1 -1
  15. package/lib/node/ext/circle.js +1 -2
  16. package/lib/node/ext/circle.js.map +1 -1
  17. package/lib/node/ext/particle.js +15 -65
  18. package/lib/node/ext/particle.js.map +1 -1
  19. package/lib/node/ext/rectangle.js +1 -2
  20. package/lib/node/ext/rectangle.js.map +1 -1
  21. package/lib/renderer/camera.js +0 -8
  22. package/lib/renderer/camera.js.map +1 -1
  23. package/lib/renderer/renderer.js +2 -7
  24. package/lib/renderer/renderer.js.map +1 -1
  25. package/lib/types/asset/audio.d.ts +8 -0
  26. package/lib/types/asset/audio.d.ts.map +1 -1
  27. package/lib/types/dom/dom-particle.d.ts +0 -1
  28. package/lib/types/dom/dom-particle.d.ts.map +1 -1
  29. package/lib/types/node/core/game-object.d.ts +1 -3
  30. package/lib/types/node/core/game-object.d.ts.map +1 -1
  31. package/lib/types/node/core/renderable.d.ts +1 -0
  32. package/lib/types/node/core/renderable.d.ts.map +1 -1
  33. package/lib/types/node/core/transformable.d.ts.map +1 -1
  34. package/lib/types/node/ext/animated-sprite.d.ts.map +1 -1
  35. package/lib/types/node/ext/bitmap-text.d.ts.map +1 -1
  36. package/lib/types/node/ext/circle.d.ts.map +1 -1
  37. package/lib/types/node/ext/particle.d.ts +0 -1
  38. package/lib/types/node/ext/particle.d.ts.map +1 -1
  39. package/lib/types/node/ext/rectangle.d.ts.map +1 -1
  40. package/lib/types/renderer/camera.d.ts.map +1 -1
  41. package/lib/types/renderer/renderer.d.ts.map +1 -1
  42. package/package.json +1 -1
  43. package/src/asset/audio.ts +28 -7
  44. package/src/dom/dom-particle.ts +24 -91
  45. package/src/node/core/game-object.ts +2 -10
  46. package/src/node/core/renderable.ts +5 -4
  47. package/src/node/core/transformable.ts +11 -49
  48. package/src/node/ext/animated-sprite.ts +1 -10
  49. package/src/node/ext/bitmap-text.ts +4 -70
  50. package/src/node/ext/circle.ts +1 -2
  51. package/src/node/ext/particle.ts +16 -80
  52. package/src/node/ext/rectangle.ts +1 -2
  53. package/src/renderer/camera.ts +0 -6
  54. package/src/renderer/renderer.ts +2 -9
@@ -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 = this.#acquireSprite(x, y, scale, angle)
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
- // [성능 최적화] swap-and-pop 패턴으로 O(n) splice 비용 제거
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
- // [성능 최적화] destroy 대신 풀로 반환
176
- this.#releaseSprite(g)
177
- p.active = false
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
- // [성능 최적화] Graphics 자식 노드를 가지지 않으므로 sortableChildren 불필요
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
@@ -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
  }
@@ -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.render(this._pixiContainer)
168
+ this._resetWorldTransformDirty()
169
+ this.#pixiRenderer?.render(this._pixiContainer)
177
170
  this.fpsDisplay?.update()
178
171
 
179
172
  this._isSizeDirty = false