feat: 适配关卡内图片的圆角

This commit is contained in:
richarjiang
2026-05-03 22:28:22 +08:00
parent 7249df8c22
commit c04bde38a3
13 changed files with 346 additions and 41 deletions

View File

@@ -0,0 +1,99 @@
import { EffectAsset, Material, Sprite, Vec4 } from 'cc';
/**
* 圆角 Sprite 材质工具。
*
* 基于 rounded-sprite.effect 的 SDF alpha 裁剪实现,直接作用于 Sprite 的自定义材质。
* 每个 Sprite 都会获得独立 Material避免 roundedParams / uvRect 互相覆盖。
*/
let cachedTemplate: Material | null = null;
let cachedEffectRef: EffectAsset | null = null;
const getOrCreateTemplate = (effectAsset: EffectAsset): Material => {
if (cachedTemplate && cachedEffectRef === effectAsset) {
return cachedTemplate;
}
const template = new Material();
template.initialize({
effectAsset,
defines: { USE_TEXTURE: true },
});
cachedTemplate = template;
cachedEffectRef = effectAsset;
return template;
};
const extractUvRect = (sprite: Sprite): Vec4 => {
const spriteFrame = sprite.spriteFrame;
if (!spriteFrame) {
return new Vec4(0, 0, 1, 1);
}
const uv = spriteFrame.uv;
if (!uv || uv.length < 8) {
return new Vec4(0, 0, 1, 1);
}
const u0 = uv[0];
const v0 = uv[1];
const u1 = uv[2];
const v1 = uv[3];
const u2 = uv[4];
const v2 = uv[5];
const u3 = uv[6];
const v3 = uv[7];
const minU = Math.min(u0, u1, u2, u3);
const maxU = Math.max(u0, u1, u2, u3);
const minV = Math.min(v0, v1, v2, v3);
const maxV = Math.max(v0, v1, v2, v3);
const rangeU = maxU - minU;
const rangeV = maxV - minV;
if (rangeU <= 0 || rangeV <= 0) {
return new Vec4(0, 0, 1, 1);
}
return new Vec4(minU, minV, rangeU, rangeV);
};
export const applyRoundedCorner = (
sprite: Sprite,
effectAsset: EffectAsset,
width: number,
height: number,
cornerRadius = 0.1,
grayscale = false,
): void => {
if (!sprite || !sprite.isValid) {
console.warn('[roundedMaterial] Invalid sprite, skipping');
return;
}
if (!effectAsset) {
console.warn('[roundedMaterial] EffectAsset is null, skipping');
return;
}
const template = getOrCreateTemplate(effectAsset);
const materialInstance = new Material();
const defines: Record<string, boolean> = { USE_TEXTURE: true };
if (grayscale) {
defines.IS_GRAY = true;
}
materialInstance.initialize({
effectAsset,
defines,
});
const params = new Vec4(cornerRadius, 0, width, height);
materialInstance.setProperty('roundedParams', params);
materialInstance.setProperty('uvRect', extractUvRect(sprite));
sprite.customMaterial = materialInstance;
};

View File

@@ -0,0 +1,9 @@
{
"ver": "4.0.24",
"importer": "typescript",
"imported": true,
"uuid": "216272d4-0b46-425b-be95-28e46f1417f4",
"files": [],
"subMetas": {},
"userData": {}
}