使用方法,把脚本挂在一个空节点上,把需要z轴渲染顺序的根节点挂在renderNode上,根节点和空节点属性保持一致就好
@class ZRenderRoot
@author YI ZHANG
@date 2022/7/11
@desc
**/
import * as cc from "cc";
const {ccclass, property} = cc._decorator;
let oldFunc2 = cc.UIOpacity.prototype.onEnable;
cc.UIOpacity.prototype.onEnable = function (){
oldFunc2.call(this);
// @ts-ignore
this.node._uiProps.localOpacityEx = this._opacity / 255;
}
let oldFunc3 = cc.UIOpacity.prototype.onEnable;
cc.UIOpacity.prototype.onDisable = function (){
oldFunc3.call(this);
// @ts-ignore
this.node._uiProps.localOpacityEx = 1;
}
Object.defineProperty(cc.UIOpacity.prototype,"opacity",{
get(): any {
return this._opacity;
},
set(value: any) {
if (this._opacity === value) {
return;
}
value = ZRenderRoot.clamp(value, 0, 255);
this._opacity = value;
let opacity = value / 255;
this.node._uiProps.localOpacity = opacity;
this.node._uiProps.localOpacityEx = opacity;
}
})
@ccclass("ZRenderRoot")
export default class ZRenderRoot extends cc.Component{
@property(cc.Node)
renderNode : cc.Node = null!;
v3_1 = cc.v3();
v3_2 = cc.v3();
childrenList : cc.Node[] = [];
static clamp(value : number,min : number, max :number){
return value > max ? max : (value < min ? min : value);
}
protected onLoad() {
let self = this;
Object.defineProperty(this.node,"children",{
get(): any {
return self.childrenList;
}
});
}
protected onEnable() {
this.renderNode._static = true;
cc.director.on(cc.Director.EVENT_BEFORE_DRAW,()=>{//发出渲染前事件供自定义组件更新脏视图
this.childrenList = this.getChildrenList();
},this);
}
static forEachNode(node : cc.Node,fn : (node : cc.Node)=>boolean | void){
if(fn(node)){
return true;
}
let children = node.children;
for(let i = 0;i < children.length;++i){
if(this.forEachNode(children[i],fn)){
return true;
}
}
return false;
}
protected onDisable() {
this.renderNode._static = false;
ZRenderRoot.forEachNode(this.renderNode,node => {
node._static = false;
})
this.childrenList.length = 0;
cc.director.targetOff(this);
}
getChildrenList(){
let list : cc.Node[] = [];
let i = 0;
ZRenderRoot.forEachNode(this.renderNode,node => {
node._static = true;
// @ts-ignore
node._indexEx = i++;
list.push(node);
})
list.sort((a,b)=>{
let aZ = b.getWorldPosition(this.v3_2).z;
let bZ = a.getWorldPosition(this.v3_1).z;
if(aZ != bZ){
return aZ - bZ;
}
// @ts-ignore
return a._indexEx - b._indexEx;
});
this.walk(this.renderNode,1);
return list;
}
walk(node : cc.Node,opacity : number){
// @ts-ignore
let localOpacity = node._uiProps.localOpacityEx === undefined ? 1 : node._uiProps.localOpacityEx;
// @ts-ignore
opacity = opacity * localOpacity ;
node._uiProps.localOpacity = opacity;
if(node._uiProps.uiComp){
node.layer = 1 << 30;
}
let children = node.children;
let length = children.length;
for(let i = 0;i < length;++i){
this.walk(children[i],opacity);
}
}
}