Created
July 14, 2022 06:52
-
-
Save dxball/5a7c6849cadac5a02d778c4eda30fd42 to your computer and use it in GitHub Desktop.
Cocos 3.X Gradient
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import { _decorator, Color, Component, Renderable2D } from "cc"; | |
const { | |
ccclass, | |
property, | |
requireComponent, | |
disallowMultiple, | |
executeInEditMode, | |
} = _decorator; | |
/** | |
* 漸層色,支援 Sprite (Simple & Filled), Label (TTF Font) | |
* @reference https://github.com/ifaswind/cocos-eazax-kit/blob/develop/components/renderers/GradientColor.ts | |
*/ | |
@ccclass("UIGradientColor") | |
@requireComponent(Renderable2D) | |
@disallowMultiple | |
@executeInEditMode | |
export class UIGradientColor extends Component { | |
@property({ visible: true, tooltip: "左下" }) | |
protected _colorLB: Color = Color.RED.clone(); | |
@property({ visible: true, tooltip: "右下" }) | |
protected _colorRB: Color = Color.BLUE.clone(); | |
@property({ visible: true, tooltip: "左上" }) | |
protected _colorLT: Color = Color.YELLOW.clone(); | |
@property({ visible: true, tooltip: "右上" }) | |
protected _colorRT: Color = Color.GREEN.clone(); | |
private _isEnable: boolean = true; | |
/** | |
* 取得或設定漸層顏色,[左下、右下、左上、右上] | |
*/ | |
public get colors(): Readonly<Color>[] { | |
return [this._colorLB, this._colorRB, this._colorLT, this._colorRT]; | |
} | |
public set colors(colors: ReadonlyArray<Color>) { | |
if (colors.length < 4) return; | |
[this._colorLB, this._colorRB, this._colorLT, this._colorRT] = colors; | |
this.markForRender(); | |
} | |
/** | |
* 左上 | |
*/ | |
public get colorLT(): Readonly<Color> { | |
return this._colorLT; | |
} | |
public set colorLT(color: Color) { | |
if (this._colorLT.equals(color)) return; | |
this._colorLT.set(color); | |
this.markForRender(); | |
} | |
/** | |
* 右上 | |
*/ | |
public get colorRT(): Readonly<Color> { | |
return this._colorRT; | |
} | |
public set colorRT(color: Color) { | |
if (this._colorRT.equals(color)) return; | |
this._colorRT.set(color); | |
this.markForRender(); | |
} | |
/** | |
* 左下 | |
*/ | |
public get colorLB(): Readonly<Color> { | |
return this._colorLB; | |
} | |
public set colorLB(color: Color) { | |
if (this._colorLB.equals(color)) return; | |
this._colorLB.set(color); | |
this.markForRender(); | |
} | |
/** | |
* 右下 | |
*/ | |
public get colorRB(): Readonly<Color> { | |
return this._colorRB; | |
} | |
public set colorRB(color: Color) { | |
if (this._colorRB.equals(color)) return; | |
this._colorRB.set(color); | |
this.markForRender(); | |
} | |
onEnable() { | |
this._isEnable = true; | |
this.replaceFunction(); | |
} | |
onDisable() { | |
this._isEnable = false; | |
this.restoreFunction(); | |
} | |
onDestroy() { | |
this._isEnable = false; | |
this.restoreFunction(); | |
} | |
resetInEditor() { | |
this.replaceFunction(); | |
} | |
/** | |
* 把 IAssembler2D.updateColor 換成自訂的 | |
*/ | |
protected replaceFunction() { | |
const renderComp = this.getComponent(Renderable2D); | |
if (!renderComp) return; | |
const assembler = renderComp["_assembler"]; | |
if (!assembler) return; | |
// 這邊取到的 Assembler 是元件共用的,所以設計成先把舊的 updateColor 記錄下來 | |
// 當呼叫 updateColor 時先檢查元件是否有掛上 UIGradientColor,如果沒有的話就呼叫元件本身的 | |
const originalUpdateColor = assembler["_originalUpdateColor"]; | |
if (!originalUpdateColor) { | |
// 備份原有的 updateColor | |
assembler["_originalUpdateColor"] = assembler["updateColor"]; | |
// 替换顏色填充 Function | |
assembler["updateColor"] = UIGradientColor.OnAssemblerUpdateColor; | |
} | |
// 标记 | |
this.markForRender(); | |
} | |
private static OnAssemblerUpdateColor(comp: Renderable2D) { | |
let gradient = comp.node.getComponent(UIGradientColor); | |
if (gradient == null) { | |
const comps = comp.node.components; | |
for (let i = 0; i < comps.length; i++) { | |
const tmpComp = comps[i]; | |
if (tmpComp instanceof UIGradientColor) { | |
gradient = tmpComp; | |
break; | |
} | |
} | |
} | |
if (gradient && gradient._isEnable) { | |
const renderData = comp.renderData; | |
if (renderData == null) return; | |
if (renderData.chunk == null) return; | |
// 取得頂點顏色資料 | |
const vData = renderData.chunk.vb; | |
if (!vData) return; | |
let colorOffset = 5; // 偏移 | |
const colors = [ | |
gradient._colorLB, | |
gradient._colorRB, | |
gradient._colorLT, | |
gradient._colorRT, | |
]; | |
// 設定頂點顏色 | |
for (let i = 0; i < 4; i++, colorOffset += renderData.floatStride) { | |
vData[colorOffset] = colors[i].r / 255; | |
vData[colorOffset + 1] = colors[i].g / 255; | |
vData[colorOffset + 2] = colors[i].b / 255; | |
vData[colorOffset + 3] = colors[i].a / 255; | |
} | |
} else { | |
const _assembler = comp["_assembler"]; | |
if (_assembler) { | |
_assembler["_originalUpdateColor"]?.(comp); | |
} | |
} | |
} | |
/** | |
* 還原 | |
*/ | |
protected restoreFunction() { | |
const renderComp = this.getComponent(Renderable2D); | |
if (!renderComp) return; | |
const assembler = renderComp["_assembler"]; | |
if (!assembler) return; | |
renderComp.destroyRenderData(); | |
renderComp["_flushAssembler"]?.(); | |
this.markForRender(); | |
} | |
/** | |
* 更新顏色 | |
*/ | |
public markForRender() { | |
const renderComp = this.getComponent(Renderable2D); | |
if (!renderComp) return; | |
renderComp["_updateColor"]?.(); | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment