import * as cc from "cc"; class node_extends { constructor(node_: cc.Node) { this._node = node_; this._node.components.forEach((v) => { if (v instanceof cc.Label) { this.label = v; } else if (v instanceof cc.Sprite) { this.sprite = v; } else if (v instanceof cc.UIOpacity) { this.ui_opacity = v; } else if (v instanceof cc.UITransform) { this.ui_transform = v; } else if (v instanceof cc.Animation) { this.animation = v; } else if (v instanceof cc.EditBox) { this.edit_box = v; } else if (v instanceof cc.RichText) { this.rich_text = v; } else if (v instanceof cc.Layout) { this.layout = v; } else if (v instanceof cc.ProgressBar) { this.progress_bar = v; } else if (v instanceof cc.Slider) { this.slider = v; } else if (v instanceof cc.Toggle) { this.toggle = v; } }); } /* --------------- static --------------- */ /** 节点扩展数据 */ static node_extends_map = new Map(); /** 渲染顺序更新倒计时 */ static order_update_timer: any = null; /** 渲染顺序更新时间 */ private static _order_update_time_n = 0; /** 更新任务 */ private static _order_update_task_fs: Function[] = []; /* --------------- public --------------- */ label!: cc.Label; sprite!: cc.Sprite; ui_opacity!: cc.UIOpacity; ui_transform!: cc.UITransform; animation!: cc.Animation; edit_box!: cc.EditBox; rich_text!: cc.RichText; layout!: cc.Layout; progress_bar!: cc.ProgressBar; slider!: cc.Slider; toggle!: cc.Toggle; /** 节点渲染次序 */ // eslint-disable-next-line @typescript-eslint/naming-convention get order_n(): number { return this._order_n; } set order_n(value_n_: number) { this._set_order_n(value_n_); } /** 宽 */ get width(): number { return this.ui_transform.width; } set width(value_n_) { this.ui_transform.width = value_n_; } /** 高 */ get height(): number { return this.ui_transform.height; } set height(value_n_) { this.ui_transform.height = value_n_; } /** 透明度 */ get opacity(): number { return this.ui_opacity.opacity; } set opacity(value_n_) { this.ui_opacity.opacity = value_n_; } /** 锚点 */ get anchor(): Readonly { return this.ui_transform.anchorPoint; } set anchor(value_v2_: cc.Vec2) { this.ui_transform.anchorPoint = value_v2_; } /* --------------- private --------------- */ /** 持有节点 */ private _node: cc.Node; /** 节点渲染次序 */ // eslint-disable-next-line @typescript-eslint/naming-convention private _order_n = 0; /* ------------------------------- 功能 ------------------------------- */ /* ------------------------------- get/set ------------------------------- */ private _set_order_n(value_n_: number): void { if ( // 未改变渲染顺序 this._order_n === value_n_ || // 节点失效 !this._node.isValid ) { return; } /** 父节点层级数据 */ const parent = N(this._node.parent!); if (!parent) { this._node.once( cc.Node.EventType.PARENT_CHANGED, () => { // 延迟一帧避免 children 数据未更新 setTimeout(() => { this._set_order_n(value_n_); }, 0); }, this ); return; } // 更新渲染顺序 this._order_n = value_n_; /** 距离上次更新的时间 */ const time_since_last_update_n = Date.now() - node_extends._order_update_time_n; // 添加任务 node_extends._order_update_task_fs.push((): void => { // (节点/父节点)失效 if (!this._node.isValid || !parent._node.isValid || this._node.parent !== parent._node) { return; } /** 同级节点 */ const node_as = [...parent._node.children].sort((va, vb) => (N(va, false)?._order_n ?? 0) - (N(vb, false)?._order_n ?? 0)); // 更新渲染顺序 node_as.forEach((v, k_n) => { v.setSiblingIndex(k_n); }); }); // 已经准备更新 if (node_extends.order_update_timer !== null) { return; } // 小于间隔时间更新 if (node_extends.order_update_timer === null && time_since_last_update_n < cc.game.frameTime) { node_extends.order_update_timer = setTimeout(() => { // 清理定时器数据 node_extends.order_update_timer = null; // 更新时间 node_extends._order_update_time_n = Date.now(); // 更新渲染顺序 node_extends._order_update_task_fs.splice(0, node_extends._order_update_task_fs.length).forEach((v_f) => v_f()); }, cc.game.frameTime - time_since_last_update_n); return; } // 延迟一帧避免同帧内使用 children 下标获取节点不正确 setTimeout(() => { // 更新时间 node_extends._order_update_time_n = Date.now(); // 更新渲染顺序 node_extends._order_update_task_fs.splice(0, node_extends._order_update_task_fs.length).forEach((v_f) => v_f()); }, 0); } } // eslint-disable-next-line @typescript-eslint/naming-convention function N(node_: cc.Node, force_b_ = true): node_extends { if (!node_?.isValid) { return null!; } let node_extend = node_extends.node_extends_map.get(node_) ?? null; if (!node_extend && force_b_) { node_extend = new node_extends(node_); node_extends.node_extends_map.set(node_, node_extend); } return node_extend!; } namespace N { /** order 刷新间隔时间(毫秒) */ export const order_refresh_interval_ms_n = cc.game.frameTime; /** 清理节点数据 */ export function clear(): void { // 清理定时器 if (node_extends.order_update_timer) { clearTimeout(node_extends.order_update_timer); node_extends.order_update_timer = null; } // 清理节点数据 node_extends.node_extends_map.clear(); } } // 切换场景后自动清理 cc.director.on(cc.Director.EVENT_BEFORE_SCENE_LAUNCH, N.clear, this); export default N;