2D Game Engine

Zasoby (AssetManager)

Manifest, statusy ładowania, uchwyty właścicieli, refcounting, GC i raporty rozmiarów. Jak ładować assety bez wycieków.

Typy zasobów#

image · spritesheet · atlas · audio · bitmapFont · json · tilemap

Klucz animacji z spritesheeta ma format <assetId>:<key>.

Deklaracja i ładowanie#

Assety deklarujesz w scenie, a ładujesz tylko w preload:

ts
class GameScene extends Scene {
  declareAssets(assets: AssetDescriptor[]) {
    super.declareAssets([
      { id: 'hero', type: 'spritesheet', src: '/assets/hero.png', frameWidth: 32, frameHeight: 32 },
      { id: 'tileset', type: 'tilemap', src: '/assets/level1.json' },
      { id: 'music', type: 'audio', src: '/assets/theme.ogg' },
      { id: 'pl', type: 'json', src: '/assets/i18n/pl.json' }
    ])
  }

  async preload() {
    this.getAssets().onProgress(({ loaded, total }) => {
      this.loadingBar.setProgress(loaded / total)
    })
    await this.getAssets().load()
  }
}

Statusy#

text
idle → queued → loading → ready
                        ↘ failed
ts
const assets = this.getAssets()

assets.status('hero')
assets.isLoaded('hero')
assets.hasTexture('hero')
assets.pending()
assets.failuresList()
assets.retry(['hero'])
assets.cancel()

API#

ts
register(descriptor); registerMany(list); setManifest(m); getManifest()
has(id); isLoaded(id); hasTexture(id); get(id); getAll(); pending(); count()
status(id): "idle" | "queued" | "loading" | "ready" | "failed"
animations(); attachBackend(backend); detachBackend()
queue(); load(ids?); cancel(): boolean; retry(ids?): number
failuresList(); report(); sizeReport(limits?); formatSizes(limits?)

hold(owner, ids); releaseOwner(owner): number
retain(id); release(id); releaseGroup(group); isRetained(id); gc()
unload(id)
onProgress(h); onError(h); onLoaded(h)

Uchwyty właścicieli i refcounting#

Każdy zasób ma licznik odwołań. Scena trzyma zasoby przez hold, a przy shutdown silnik woła releaseOwner:

ts
assets.hold('game', ['hero', 'tileset'])

assets.retain('hero')
assets.release('hero')
assets.gc()

Zero wycieków między scenami

Nie musisz pamiętać o zwalnianiu assetów — shutdown() sceny robi releaseOwner automatycznie. gc() usuwa tylko zasoby z zerowym refcountem.

Raporty i budżet rozmiarów#

ts
const report = assets.sizeReport({ image: 2_000_000, audio: 5_000_000 })
console.log(assets.formatSizes({ image: 2_000_000 }))

const diagnosis = assets.diagnose({ usedIds: ['hero'], references: [] })

diagnose() zwraca registered, unused, missing, failed, unlicensed i heaviest — gotowe do raportu diagnostycznego.

Przykład: ekran ładowania#

ts
class BootScene extends Scene {
  async preload() {
    const bar = this.createRect(0, 8, { x: 240, y: 360, fill: '#5b63d3' })
    this.getAssets().onProgress(({ loaded, total }) => {
      bar.setScale(total ? loaded / total : 0, 1)
    })
    await this.getAssets().load()
  }

  create() {
    this.getEvents().emit('request:scene', { to: 'menu' })
  }
}