import { describe, expect, test } from 'vitest'; import { buildMatch3DItemSpritesheetViewRegions, detectMatch3DSpritesheetRegions, } from './match3dSpritesheetParser'; describe('match3dSpritesheetParser', () => { test('按透明像素连通域检测素材并按从上到下从左到右排序', () => { const width = 12; const height = 10; const alpha = new Uint8ClampedArray(width * height); const paint = (x0: number, y0: number, x1: number, y1: number) => { for (let y = y0; y <= y1; y += 1) { for (let x = x0; x <= x1; x += 1) { alpha[y * width + x] = 255; } } }; paint(8, 1, 10, 3); paint(1, 1, 3, 2); paint(5, 6, 7, 8); const regions = detectMatch3DSpritesheetRegions({ alpha, width, height, labels: ['返回', '设置', '移出'], }); expect(regions).toEqual([ { height: 2, label: '返回', width: 3, x: 1, y: 1 }, { height: 3, label: '设置', width: 3, x: 8, y: 1 }, { height: 3, label: '移出', width: 3, x: 5, y: 6 }, ]); }); test('忽略小噪点,只返回可用矩形素材', () => { const width = 8; const height = 8; const alpha = new Uint8ClampedArray(width * height); alpha[0] = 255; for (let y = 2; y <= 5; y += 1) { for (let x = 2; x <= 5; x += 1) { alpha[y * width + x] = 255; } } const regions = detectMatch3DSpritesheetRegions({ alpha, width, height, labels: ['方格'], minArea: 4, }); expect(regions).toEqual([ { height: 4, label: '方格', width: 4, x: 2, y: 2 }, ]); }); test('按10行10列图集顺序把每行两种物品拆成五视角', () => { const regions = Array.from({ length: 100 }, (_, index) => ({ label: `素材${index + 1}`, x: (index % 10) * 10, y: Math.floor(index / 10) * 10, width: 8, height: 8, })); const grouped = buildMatch3DItemSpritesheetViewRegions(regions, [ '草莓', '苹果', '毛肚', ]); expect(grouped).toHaveLength(20); expect(grouped[0]).toEqual({ itemIndex: 0, itemName: '草莓', regions: regions.slice(0, 5).map((region, index) => ({ ...region, label: `草莓-形态${index + 1}`, })), }); expect(grouped[1]).toEqual({ itemIndex: 1, itemName: '苹果', regions: regions.slice(5, 10).map((region, index) => ({ ...region, label: `苹果-形态${index + 1}`, })), }); expect(grouped[2]?.itemName).toBe('毛肚'); expect(grouped[19]?.regions).toHaveLength(5); }); });