import { _decorator, UIRenderer, Component, Color, clamp, director, Director, Sprite, Label } from 'cc'; import { DEV, JSB } from 'cc/env'; const { ccclass, property, executeInEditMode, requireComponent, menu } = _decorator; @ccclass @executeInEditMode @requireComponent(UIRenderer) @menu('Public/Palette') export class Palette extends Component { @property private _colorLB: Color = new Color(255, 255, 255, 255); @property({ displayName: DEV && '↙ 左下' }) public get colorLB() { return this._colorLB }; public set colorLB(value: Color) { this._colorLB = value; this.updateColor(); } @property private _colorRB: Color = new Color(255, 255, 255, 255); @property({ displayName: DEV && '↘ 右下' }) public get colorRB() { return this._colorRB }; public set colorRB(value: Color) { this._colorRB = value; this.updateColor(); } @property private _colorLT: Color = new Color(255, 255, 255, 255); @property({ displayName: DEV && '↖ 左上' }) private get colorLT() { return this._colorLT }; private set colorLT(value: Color) { this._colorLT = value; this.updateColor(); } @property private _colorRT: Color = new Color(255, 255, 255, 255); @property({ displayName: DEV && '↗ 右上' }) private get colorRT() { return this._colorRT }; private set colorRT(value: Color) { this._colorRT = value; this.updateColor(); } @property private _hueRatio: number = 1; @property({ range: [0, 1], step: 0.01, slide: true, displayName: '🌈 色相' }) get hueRatio() { return this._hueRatio; } set hueRatio(val) { this._hueRatio = clamp(val, 0, 1); this.updateHueRatio(); this.updateColor(); } @property private _darkness: number = 1; @property({ range: [0, 1], step: 0.01, slide: true, displayName: '🌞 暗度' }) get darkness() { return this._darkness; } set darkness(val) { this._darkness = clamp(val, 0, 1); this.updateColor(); } private ur: UIRenderer = null; private hue: number[] = [1, 1, 1]; //色相分量 protected onLoad() { this.ur = this.node.getComponent(UIRenderer); if (!(this.ur instanceof Sprite || this.ur instanceof Label)) { console.warn('Palette只对Sprite和Label有效!'); this.destroy(); return; } this.ur['_useVertexOpacity'] = true; //启用顶点透明度(否则透明度只受color.a影响) } protected onEnable() { this.updateHueRatio(); director.once(Director.EVENT_AFTER_DRAW, this.updateColor, this); } protected onDisable() { if (!this.ur['_renderData']) return; let vb = this.ur['_renderData'].chunk.vb; let color = this.ur.color; vb[5] = vb[14] = vb[23] = vb[32] = color.r / 255; vb[6] = vb[15] = vb[24] = vb[33] = color.g / 255; vb[7] = vb[16] = vb[25] = vb[34] = color.b / 255; vb[8] = vb[17] = vb[26] = vb[35] = color.a / 255; } private updateColor() { let vb = this.ur['_renderData'].chunk.vb; let lb = this._colorLB, rb = this._colorRB, lt = this._colorLT, rt = this._colorRT; let d = this._darkness / 255, h = this.hue, r = h[0] * d, g = h[1] * d, b = h[2] * d; vb[5] = lb.r * r; vb[6] = lb.g * g; vb[7] = lb.b * b; vb[8] = lb.a / 255; vb[14] = rb.r * r; vb[15] = rb.g * g; vb[16] = rb.b * b; vb[17] = rb.a / 255; vb[23] = lt.r * r; vb[24] = lt.g * g; vb[25] = lt.b * b; vb[26] = lt.a / 255; vb[32] = rt.r * r; vb[33] = rt.g * g; vb[34] = rt.b * b; vb[35] = rt.a / 255; } private updateHueRatio(): void { const step = 1 / 7; let hueRatio = this._hueRatio; if (hueRatio < step) this.hue = [1, hueRatio / step, 0]; else if (hueRatio < step * 2) this.hue = [2 - hueRatio / step, 1, 0]; else if (hueRatio < step * 3) this.hue = [0, 1, hueRatio / step - 2]; else if (hueRatio < step * 4) this.hue = [0, 4 - hueRatio / step, 1]; else if (hueRatio < 5 * step) this.hue = [hueRatio / step - 4, 0, 1]; else if (hueRatio < 6 * step) this.hue = [1, 0, 6 - hueRatio / step]; else { this.hue = [1, hueRatio / step - 6, hueRatio / step - 6]; } } }