MatchMaster/assets/Script/BattlePassArt.ts
2026-10-09 17:53:38 +08:00

75 lines
4.5 KiB
TypeScript

/** Shared image assets for the settlement, unlock presentation and Halloween digits. */
export default class BattlePassArt {
static frames: { [name: string]: cc.SpriteFrame } = {};
private static pending: Promise<void>;
static settlementPrefab: cc.Prefab;
static unlockPrefab: cc.Prefab;
private static halloween: Promise<void>;
static loadHalloween(): Promise<void> {
if (!this.halloween) this.halloween = (async () => {
const names = ['pumpkin_normal','pumpkin_active','time_bg','slash'];
for (const group of ['digits_progress','digits_level_large','digits_level_small']) for (let i=0;i<10;i++) names.push(group+'/'+i);
await Promise.all(names.map(n => this.loadAsset('passCheck','img/halloween/'+n,cc.SpriteFrame).then(f => {this.frames[n]=f;})));
})().catch(e => {this.halloween=null;throw e;});
return this.halloween;
}
static digits(target: cc.Node, value: number, disabled = false) {
const ticket = ((target as any)._passDigitsTicket || 0) + 1; (target as any)._passDigitsTicket=ticket;
this.loadHalloween().then(() => {
if (!cc.isValid(target) || (target as any)._passDigitsTicket!==ticket) return;
const progress=target.name==='progress_1'||target.name==='progress_2';
const group=progress?'digits_progress':disabled?'digits_level_small':'digits_level_large';
const chars=String(value).split(''), spacing=progress?28:40;
target.destroyAllChildren();
chars.forEach((d,i) => {
const sprite = this.image(target,group+'/'+d,(i-(chars.length-1)/2)*spacing,0).getComponent(cc.Sprite);
sprite.trim = false;
sprite.sizeMode = cc.Sprite.SizeMode.RAW;
});
if(!progress&&target.parent) {
const pumpkin=target.parent.getChildByName('bright_bg');
if(pumpkin) { pumpkin.getComponent(cc.Sprite).spriteFrame=this.frames[disabled?'pumpkin_normal':'pumpkin_active']; pumpkin.setContentSize(140,140); }
}
}).catch(e=>cc.warn('战令数字素材加载失败',e));
}
static loadAsset(bundle: string, path: string, type: any): Promise<any> {
return new Promise((resolve, reject) => {
const load = (b: cc.AssetManager.Bundle) => b.load(path, type, (e, a) => e ? reject(e) : resolve(a));
const b = cc.assetManager.getBundle(bundle);
if (b) load(b);
else cc.assetManager.loadBundle(bundle, (e, loaded) => e ? reject(e) : load(loaded));
});
}
static load(): Promise<void> {
if (this.pending) return this.pending;
this.pending = Promise.all([
this.loadAsset('passCheck','prefab/PassSettlement',cc.Prefab).then(p => { this.settlementPrefab = p; }),
this.loadAsset('passCheck','prefab/PassUnlock',cc.Prefab).then(p => { this.unlockPrefab = p; })
]).then(() => {}).catch(e => { this.pending = null; throw e; });
return this.pending;
}
static image(parent: cc.Node, name: string, x: number, y: number, width?: number, height?: number): cc.Node {
const n = new cc.Node(name); n.parent = parent; n.setPosition(x, y);
const sprite = n.addComponent(cc.Sprite); sprite.spriteFrame = this.frames[name];
sprite.sizeMode = cc.Sprite.SizeMode.CUSTOM;
const size = sprite.spriteFrame.getOriginalSize();
n.setContentSize(width || size.width, height || size.height);
return n;
}
static async unlock(parent: cc.Node, tier: number, done: () => void) {
await this.load();
if (!cc.isValid(parent)) return;
const root = cc.instantiate(this.unlockPrefab); root.parent = parent; root.zIndex = 1100;
const content = root.getChildByName('content');
content.scaleX *= Math.min(parent.width / root.width, parent.height / root.height);
content.scaleY *= Math.min(parent.width / root.width, parent.height / root.height);
const vip = content.getChildByName('vip'), svip = content.getChildByName('svip');
vip.active = tier === 18; svip.active = tier !== 18;
const card = (vip.active ? vip : svip).getChildByName('cardAnimation');
const scaleX = card.scaleX, scaleY = card.scaleY;
card.scale = 0; let ready = false;
cc.tween(card).to(0.35,{scaleX,scaleY},{easing:'backOut'}).delay(0.4).call(() => {ready=true;}).start();
root.getChildByName('shade').on(cc.Node.EventType.TOUCH_END, () => { if (ready) { root.destroy(); done(); } });
}
}