MatchMaster/assets/Script/module/Tool/GameplayAtlasFrames.ts

49 lines
2.4 KiB
TypeScript

/** 图集位置由同版本远程 plist 决定,不再内置固定裁剪坐标。 */
export const GAMEPLAY_ATLAS_PATHS = ["BlockBtnUI", "door", "down"];
export interface GameplayAtlasLayout {
width: number;
height: number;
// [x, y, width, height, rotated, offsetX, offsetY, originalWidth, originalHeight]
frames: { [name: string]: number[] };
}
export function isGameplayAtlas(path: string): boolean {
return GAMEPLAY_ATLAS_PATHS.indexOf(path) >= 0;
}
/** Cocos 2.4 的 plist parser 已将 XML 转为对象;这里检查 TexturePacker format 2 的布局。 */
export function parseGameplayAtlas(data: any, atlas: string): GameplayAtlasLayout {
const fail = () => new Error("图集 plist 无效或与 PNG 不匹配: " + atlas);
if (!data || !data.metadata || data.metadata.format !== 2 || !data.frames) throw fail();
const numbers = (value: any, count: number): number[] => {
if (typeof value !== "string" || !/^[\s{},.\d-]+$/.test(value)) throw fail();
const matches = value.match(/-?\d+(?:\.\d+)?/g) || [];
const result = matches.map(Number);
if (result.length !== count || result.some(n => !Number.isFinite(n))) throw fail();
return result;
};
const size = numbers(data.metadata.size, 2);
if (size.some(n => n <= 0 || !Number.isInteger(n))) throw fail();
const textureName = data.metadata.textureFileName || data.metadata.realTextureFileName;
if (textureName !== atlas + ".png") throw fail();
const frames: { [name: string]: number[] } = Object.create(null);
for (const filename of Object.keys(data.frames)) {
const source = data.frames[filename];
const rect = numbers(source.frame, 4);
const offset = numbers(source.offset, 2);
const original = numbers(source.sourceSize, 2);
if (typeof source.rotated !== "boolean") throw fail();
const rotated = source.rotated;
const [x, y, w, h] = rect;
if (rect.some(n => !Number.isInteger(n)) || x < 0 || y < 0 || w <= 0 || h <= 0
|| original.some(n => n <= 0 || !Number.isInteger(n))
|| x + (rotated ? h : w) > size[0] || y + (rotated ? w : h) > size[1]) throw fail();
const name = filename.replace(/\.png$/, "");
if (!name || frames[name]) throw fail();
frames[name] = rect.concat(rotated ? 1 : 0, offset, original);
}
if (!Object.keys(frames).length) throw fail();
return { width: size[0], height: size[1], frames };
}