RenderAlternative.ts 8.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238
  1. import { _decorator, Node, Component, UIRenderer, Mat4, Vec3, director, UITransform, instantiate, sys, UIOpacity, Label } from "cc";
  2. import { RenderReactiveHandler } from "./RenderReactiveHandler";
  3. /**
  4. * 目前该渲染代理功能存在的问题
  5. * 1.被代理节点的父级不能出现scaleX和scaleY不一致的情况,被代理节点本身没有这个限制
  6. */
  7. const { ccclass, property } = _decorator;
  8. @ccclass
  9. export default class RenderAlternative extends Component {
  10. private static _isDirty: WeakMap<Node, boolean> = new WeakMap();
  11. public static isDirty(renderLayer: Node): boolean {
  12. return this._isDirty.has(renderLayer) ? this._isDirty.get(renderLayer) : false;
  13. }
  14. public static setDirty(renderLayer: Node) {
  15. if (renderLayer && !this.isDirty(renderLayer)) {
  16. this._isDirty.set(renderLayer, true);
  17. this.sortOnce(renderLayer);
  18. }
  19. };
  20. public static sortOnce(renderLayer: Node) {
  21. requestAnimationFrame(() => {
  22. renderLayer.children.sort(this.sortChildren)
  23. this._isDirty.set(renderLayer, false);
  24. })
  25. }
  26. private static sortChildren(a: Node, b: Node) {
  27. //@ts-ignore
  28. let aindex = a._rZIndex, bindex = b._rZIndex;
  29. if (Number.isFinite(aindex) && Number.isFinite(bindex)) {
  30. return aindex - bindex;
  31. } else if (!Number.isFinite(aindex)) {
  32. return 1;
  33. } else {
  34. return -1;
  35. }
  36. }
  37. /**渲染层节点 */
  38. @property(Node)
  39. public renderLayer: Node = null;
  40. /**渲染的zIndex */
  41. @property
  42. public renderZIndex: number = 0;
  43. /**同步的间隔(帧为单位) */
  44. @property({
  45. tooltip: '设置同步的间隔(秒为单位),0就是每帧都同步,0.1就是隔0.1秒同步一次'
  46. })
  47. public syncInv: number = 0.01;
  48. /**渲染的sIndex */
  49. public sIndex: number = 0;
  50. /**非渲染组件 */
  51. public proxyRender: UIRenderer = null;
  52. /**渲染组件 */
  53. private renderCompnent: UIRenderer = null;
  54. /**渲染节点的ui控件 */
  55. private renderUiTrans: UITransform = null;
  56. /**ui控件 */
  57. private uiTrans: UITransform = null;
  58. /**上次更新的数据 */
  59. public lastWMat4: Mat4 = null;
  60. /**上次更新的数据 */
  61. public lastLMat4: Mat4 = null;
  62. /**上次更新的数据 */
  63. public lastPos: Vec3 = null;
  64. /**距离下次刷新累计了多少间隔 */
  65. public accuTime: number = 0;
  66. /**最后一次刷新时间 */
  67. public lastFrameTime: number = null;
  68. /**是否进行刷新 */
  69. public isAttachFrame: boolean = false;
  70. /**获取总的ZIndex */
  71. get zIndex() {
  72. let zIndex = this.renderZIndex + (this.sIndex * 0.01);
  73. let parentNode = this.node.parent;
  74. while (parentNode != this.renderLayer?.parent && parentNode != director.getScene()) {
  75. let render = parentNode.getComponent(RenderAlternative);
  76. if (render) {
  77. zIndex += render.zIndex + 1;
  78. break;
  79. }
  80. parentNode = parentNode.parent;
  81. }
  82. return zIndex;
  83. }
  84. /**
  85. * 设置渲染节点层
  86. * @param layer
  87. */
  88. init<T extends UIRenderer>(layer?: Node): T {
  89. if (layer) {
  90. this.renderLayer = layer;
  91. }
  92. if (!this.renderLayer) {
  93. console.warn(`节点${this.node.name}没有设置渲染层`)
  94. return null;
  95. }
  96. return this.initRender<T>();
  97. }
  98. /**
  99. * 初始化渲染节点
  100. */
  101. private initRender<T extends UIRenderer>(): T {
  102. let node = this.getRender();
  103. node.setParent(this.renderLayer ? this.renderLayer : director.getScene().getChildByName("Canvas"));
  104. this.isAttachFrame = true;
  105. requestAnimationFrame(this.frameUpdate.bind(this));
  106. return this.doProxy<T>();
  107. }
  108. /**生成代理 */
  109. private doProxy<T extends UIRenderer>(): T {
  110. this.proxyRender = new Proxy(this.renderCompnent, new RenderReactiveHandler()) as T;
  111. return this.proxyRender as T;
  112. }
  113. protected frameUpdate(): void {
  114. let now = sys.now();
  115. !this.lastFrameTime && (this.lastFrameTime = now);
  116. let dt = (now - this.lastFrameTime) / 1000;
  117. this.lastFrameTime = now;
  118. if (this.proxyRender) {
  119. this.accuTime += dt;
  120. if (this.accuTime >= this.syncInv) {
  121. this.accuTime -= this.syncInv;
  122. this.updateProp();
  123. }
  124. }
  125. if (this.isAttachFrame) {
  126. requestAnimationFrame(this.frameUpdate.bind(this));
  127. }
  128. }
  129. /**更新最新状态 */
  130. public updateProp() {
  131. let node = this.renderCompnent.node;
  132. let uiTrans = this.renderUiTrans;
  133. if (!this.node.activeInHierarchy) {
  134. node.active = false;
  135. return;
  136. }
  137. node.active = true;;
  138. uiTrans.anchorX != this.uiTrans.anchorX && (uiTrans.anchorX = this.uiTrans.anchorX);
  139. uiTrans.anchorY != this.uiTrans.anchorY && (uiTrans.anchorY = this.uiTrans.anchorY);
  140. if (uiTrans.width != this.uiTrans.width) {
  141. uiTrans.width = this.uiTrans.width;
  142. if (this.renderCompnent instanceof Label) {
  143. requestAnimationFrame(() => {
  144. this.uiTrans.width = uiTrans.width;
  145. })
  146. }
  147. }
  148. if (uiTrans.height != this.uiTrans.height) {
  149. uiTrans.height = this.uiTrans.height;
  150. if (this.renderCompnent instanceof Label) {
  151. requestAnimationFrame(() => {
  152. this.uiTrans.height = uiTrans.height;
  153. })
  154. }
  155. }
  156. node.layer != this.node.layer && (node.layer = this.node.layer);
  157. let opacity = this.getOpacity(this.node);
  158. if (opacity != 255) {
  159. let uiOpacity = node.getComponent(UIOpacity) || node.addComponent(UIOpacity);
  160. uiOpacity.opacity != opacity && (uiOpacity.opacity = opacity);
  161. }
  162. let wMat4 = this.node.worldMatrix.clone();
  163. let lMat4 = this.node.matrix?.clone();
  164. if (!this.lastWMat4?.equals(wMat4) || (this.lastLMat4 && !this.lastLMat4?.equals(lMat4))) {
  165. this.onAngleChange();
  166. this.onScaleChange();
  167. this.onPosChange();
  168. this.lastLMat4 = lMat4;
  169. this.lastWMat4 = wMat4;
  170. }
  171. //@ts-ignore
  172. let old = node._rZIndex;
  173. //@ts-ignore
  174. node._rZIndex = this.zIndex;
  175. if (old != this.zIndex) {
  176. RenderAlternative.setDirty(this.renderLayer);
  177. }
  178. }
  179. protected onDestroy(): void {
  180. this.renderCompnent.node.destroy();
  181. this.renderCompnent = null;
  182. this.proxyRender = null;
  183. }
  184. /**
  185. * 获取节点透明度
  186. * @param node
  187. */
  188. private getOpacity(node: Node) {
  189. let opacity = (node.getComponent(UIOpacity)?.opacity || 255) / 255;
  190. let parentNode = node.parent;
  191. while (parentNode != this.renderLayer.parent && parentNode != director.getScene()) {
  192. opacity *= ((parentNode.getComponent(UIOpacity)?.opacity || 255) / 255);
  193. parentNode = parentNode.parent;
  194. }
  195. return opacity * 255;
  196. }
  197. /**位置变化处理 */
  198. private onPosChange() {
  199. this.renderCompnent.node.worldPosition = this.node.worldPosition.clone();
  200. }
  201. /**旋转变化处理 */
  202. private onAngleChange() {
  203. this.renderCompnent.node.worldRotation = this.node.worldRotation.clone();
  204. }
  205. /**缩放变化处理 */
  206. private onScaleChange() {
  207. this.renderCompnent.node.worldScale = this.node.worldScale.clone();
  208. }
  209. /**
  210. * 获取渲染组件
  211. * @param node
  212. */
  213. private getRender() {
  214. let node = instantiate(this.node);
  215. node.removeAllChildren();
  216. this.uiTrans = this.node.getComponent(UITransform);
  217. this.renderUiTrans = node.getComponent(UITransform);
  218. this.renderCompnent = node.getComponent(UIRenderer);
  219. this.node.getComponent(UIRenderer).destroy();
  220. for (let i = 0, len = node.components.length; i < len; ++i) {
  221. let comp = node.components[i];
  222. if (!((comp instanceof UIRenderer) || (comp instanceof UITransform))) {
  223. comp.destroy();
  224. }
  225. }
  226. return node;
  227. }
  228. }