You cannot select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
75 lines
2.5 KiB
TypeScript
75 lines
2.5 KiB
TypeScript
import { Assets, Texture } from 'pixi.js';
|
|
import {
|
|
fetchGameTextureManifest,
|
|
tryResolveGameAssetFile,
|
|
type GameTextureManifest,
|
|
} from './resolveGameAssetUrl';
|
|
import { getRequiredSpriteKeys } from './spriteMapping';
|
|
|
|
export class GameSpriteRegistry {
|
|
private _manifest: GameTextureManifest | null = null;
|
|
private _textures = new Map<string, Texture>();
|
|
private _ready = false;
|
|
|
|
private _buildFallbackManifest(keys: string[]): GameTextureManifest {
|
|
const textures: Record<string, { file: string; kind: string }> = {};
|
|
for (const key of keys) {
|
|
let file: string | null = null;
|
|
if (key.startsWith('terrain.')) file = `tiles/${key}.png`;
|
|
else if (key.startsWith('prop.')) file = `prop/${key}.png`;
|
|
else if (key.startsWith('building.')) file = `building/${key}.png`;
|
|
else if (key.startsWith('enemy.')) file = `enemies/${key}.png`;
|
|
else if (key.startsWith('npc.') || key.startsWith('hero.')) file = `characters/${key}.png`;
|
|
if (!file) continue;
|
|
textures[key] = { file, kind: 'fallback' };
|
|
}
|
|
return {
|
|
version: 0,
|
|
note: 'Fallback manifest (generated at runtime).',
|
|
textures,
|
|
};
|
|
}
|
|
|
|
get ready(): boolean {
|
|
return this._ready;
|
|
}
|
|
|
|
get manifest(): GameTextureManifest | null {
|
|
return this._manifest;
|
|
}
|
|
|
|
async loadAll(): Promise<void> {
|
|
const requiredKeys = getRequiredSpriteKeys();
|
|
try {
|
|
this._manifest = await fetchGameTextureManifest();
|
|
} catch (error) {
|
|
console.warn('[Assets] Manifest load failed, using fallback manifest.', error);
|
|
this._manifest = this._buildFallbackManifest(requiredKeys);
|
|
}
|
|
for (const key of requiredKeys) {
|
|
if (!this._manifest.textures[key]) {
|
|
console.warn(`[Assets] Missing manifest entry for sprite key: ${key}`);
|
|
}
|
|
}
|
|
const entries = Object.entries(this._manifest.textures);
|
|
await Promise.all(
|
|
entries.map(async ([key, entry]) => {
|
|
const url = tryResolveGameAssetFile(entry.file);
|
|
if (!url) {
|
|
console.warn(`[Assets] Missing sprite file in bundle: ${entry.file}`);
|
|
return;
|
|
}
|
|
const texture = await Assets.load<Texture>(url);
|
|
// Pixel-art tiles/props: nearest filtering avoids subpixel seam artifacts on tile borders.
|
|
texture.source.scaleMode = 'nearest';
|
|
this._textures.set(key, texture);
|
|
}),
|
|
);
|
|
this._ready = true;
|
|
}
|
|
|
|
getTexture(key: string): Texture | null {
|
|
return this._textures.get(key) ?? null;
|
|
}
|
|
}
|