Adds level prefabs, theme assets, audio, extensions, and deployment scripts for the Unity WebGL migration. Co-authored-by: Cursor <cursoragent@cursor.com>
90 lines
2.8 KiB
TypeScript
90 lines
2.8 KiB
TypeScript
import { JsonAsset, resources } from 'cc';
|
||
|
||
const META_PATH = 'theme/tile-display-meta';
|
||
|
||
export interface TileDisplayEntry {
|
||
width: number;
|
||
height: number;
|
||
pivotX: number;
|
||
pivotY: number;
|
||
ppu?: number;
|
||
/** 相对格子宽度的额外缩放(默认 1,snow kuai11 可略大于 1 以贴满格) */
|
||
fitMul?: number;
|
||
}
|
||
|
||
type ThemeTileMap = Record<string, TileDisplayEntry>;
|
||
|
||
let themeTiles: Record<string, ThemeTileMap> = {};
|
||
let loadPromise: Promise<void> | null = null;
|
||
|
||
function ingest(data: { themes?: Record<string, ThemeTileMap> }) {
|
||
themeTiles = { ...(data.themes ?? {}) };
|
||
}
|
||
|
||
export function loadTileDisplayMeta(): Promise<void> {
|
||
if (loadPromise) return loadPromise;
|
||
loadPromise = new Promise((resolve) => {
|
||
resources.load(META_PATH, JsonAsset, (err, asset) => {
|
||
if (err || !asset?.json) {
|
||
console.warn('[TileDisplayMeta] 未找到 tile-display-meta.json', err);
|
||
themeTiles = {};
|
||
} else {
|
||
ingest(asset.json as { themes?: Record<string, ThemeTileMap> });
|
||
}
|
||
resolve();
|
||
});
|
||
});
|
||
return loadPromise;
|
||
}
|
||
|
||
export function reloadTileDisplayMeta(): Promise<void> {
|
||
themeTiles = {};
|
||
loadPromise = null;
|
||
return new Promise((resolve) => {
|
||
resources.release(META_PATH);
|
||
loadTileDisplayMeta().then(resolve);
|
||
});
|
||
}
|
||
|
||
function normalizeThemeKey(theme?: string): string | undefined {
|
||
if (theme == null) return undefined;
|
||
const t = (typeof theme === 'string' ? theme : String(theme)).trim();
|
||
if (!t) return undefined;
|
||
if (t === 'redArmy') return 'redarmy';
|
||
return t;
|
||
}
|
||
|
||
export function getThemeTileDisplayEntry(theme: string | undefined, tileName: string): TileDisplayEntry | null {
|
||
const key = normalizeThemeKey(theme);
|
||
if (!key) return null;
|
||
const map = themeTiles[key];
|
||
if (!map) return null;
|
||
return map[tileName] ?? null;
|
||
}
|
||
|
||
export function getThemeTileSize(
|
||
theme: string | undefined,
|
||
tileName: string,
|
||
fallback: { width: number; height: number },
|
||
): { width: number; height: number } {
|
||
const entry = getThemeTileDisplayEntry(theme, tileName);
|
||
if (!entry) return fallback;
|
||
return { width: entry.width, height: entry.height };
|
||
}
|
||
|
||
export function getThemeTilePivot(
|
||
theme: string | undefined,
|
||
tileName: string,
|
||
fallback: { x: number; y: number },
|
||
): { x: number; y: number } {
|
||
const entry = getThemeTileDisplayEntry(theme, tileName);
|
||
if (!entry) return fallback;
|
||
return { x: entry.pivotX, y: entry.pivotY };
|
||
}
|
||
|
||
export function getThemeTileFitMul(theme: string | undefined, tileName: string): number {
|
||
const entry = getThemeTileDisplayEntry(theme, tileName);
|
||
const mul = entry?.fitMul ?? 1;
|
||
return Number.isFinite(mul) && mul > 0 ? mul : 1;
|
||
}
|