const { ccclass, property, requireComponent } = cc._decorator; /** 保留 fillRange 作为能量读数,改由 Shader 绘制起伏液面。 */ @ccclass @requireComponent(cc.Sprite) export default class RainbowBottleWater extends cc.Component { @property({ tooltip: "液面波浪高度(像素)", min: 0 }) waveHeight: number = 4; @property({ tooltip: "液体流动速度", min: 0 }) waveSpeed: number = 1; private sprite: cc.Sprite = null; private material: cc.Material = null; private elapsed = 0; onLoad(): void { this.sprite = this.getComponent(cc.Sprite); const frame = this.sprite.spriteFrame; const texture = frame.getTexture(); // 在异步加载材质前禁止打图集,保持液面 Shader 的 UV 范围稳定。 texture.packable = false; cc.resources.load("shader/rainbow_bottle", cc.Material, (error: Error, material: cc.Material) => { if (!cc.isValid(this, true)) return; if (error) { cc.warn("彩虹瓶子波浪材质加载失败", error); return; } this.sprite.setMaterial(0, material); this.material = this.sprite.getMaterial(0); if (cc.sys.glExtension("OES_standard_derivatives")) { this.material.define("CC_SUPPORT_standard_derivatives", true); } const rect = frame.getRect(); const rotated = frame.isRotated(); this.material.setProperty("uvRect", [rect.x / texture.width, rect.y / texture.height, (rotated ? rect.height : rect.width) / texture.width, (rotated ? rect.width : rect.height) / texture.height]); this.material.setProperty("uvRotated", rotated ? 1 : 0); this.sprite.type = cc.Sprite.Type.SIMPLE; this.lateUpdate(0); }); } lateUpdate(dt: number): void { if (!this.material) return; this.elapsed += dt * this.waveSpeed; this.material.setProperty("water", [this.sprite.fillRange, this.elapsed, this.waveHeight / this.node.height, 1 / this.node.height]); } }