const { ccclass, property } = cc._decorator; /** Reuses glyph slots authored in the prefab; no runtime node construction. */ @ccclass export default class CoinMadnessDigits extends cc.Component { @property([cc.SpriteFrame]) frames: cc.SpriteFrame[] = []; @property(cc.SpriteFrame) slashFrame: cc.SpriteFrame = null; @property height = 31; @property gap = 0; @property colonWidth = .36; private text = ''; private widthLimit = -1; private renderedWidth = 0; setText(text: string, maxWidth = 0): number { if (this.text === text && this.widthLimit === maxWidth) return this.renderedWidth; if (text.length > this.node.children.length) { cc.warn('Coin Madness digit capacity exceeded', text); return this.renderedWidth; } this.text = text; this.widthLimit = maxWidth; const glyphs = text.split('').map(char => { // The countdown separator is intentional text, never a missing-image fallback. if (char === ':') return { char, frame: null, width: this.height * this.colonWidth }; const frame = char === '/' ? this.slashFrame : this.frames[Number(char)]; const rect = frame.getRect(); return { char, frame, width: this.height * rect.width / rect.height }; }); // Bounded amounts need clear spacing, including outlines on the digit artwork. const gap = maxWidth > 0 ? Math.max(2, this.gap) : this.gap; const width = glyphs.reduce((sum, glyph) => sum + glyph.width, 0) + gap * Math.max(0, glyphs.length - 1); const scale = maxWidth > 0 && width > maxWidth ? maxWidth / width : 1; this.renderedWidth = width * scale; let x = -this.renderedWidth / 2; this.node.children.forEach((slot, i) => { slot.active = i < glyphs.length; if (!slot.active) return; const glyph = glyphs[i]; slot.x = x + glyph.width * scale / 2; const image = slot.getChildByName('Image'); image.active = glyph.char !== ':'; if (glyph.char !== ':') { image.getComponent(cc.Sprite).spriteFrame = glyph.frame; image.setContentSize(glyph.width * scale, this.height * scale); } x += (glyph.width + gap) * scale; }); return this.renderedWidth; } }