1、修复PopUp多窗口打开时,关闭一个导致PopUp层事件阻挡消失问题

2、修复Dialog窗口连续弹出时,且带关闭动画情况下,有几率后续窗口关闭不了的问题
3、扩展GUI框架可配置是否触摸非窗口区域关闭
4、扩展GUI框架可配置是否打开窗口后显示背景遮罩
5、扩展GUI框架可配置是否缓存打开的界面,使下次打开立即显示
6、重构GUI框架,代码更简洁,源API使用体验不变
This commit is contained in:
dgflash
2024-03-16 13:15:55 +08:00
parent 54726126db
commit e643839488
8 changed files with 266 additions and 255 deletions

View File

@@ -5,6 +5,7 @@
* @LastEditTime: 2023-01-09 11:52:38
*/
import { Node } from "cc";
import { UIConfig } from "./LayerManager";
/*** 界面回调参数对象定义 */
export interface UICallbacks {
@@ -23,8 +24,6 @@ export interface UICallbacks {
onRemoved?: (node: Node | null, params: any) => void,
/**
* 注意:调用`delete`或`$delete`才会触发此回调,如果`this.node.destroy()`,该回调将直接忽略。
*
* 如果指定onBeforeRemoved则next必须调用否则节点不会被正常删除。
*
* 比如希望节点做一个FadeOut然后删除则可以在`onBeforeRemoved`当中播放action动画动画结束后调用next
@@ -34,21 +33,10 @@ export interface UICallbacks {
onBeforeRemove?: (node: Node, next: Function) => void
}
/** 弹框层回调对象定义 */
export interface PopViewParams extends UICallbacks {
/** 是否触摸背景关闭弹窗 */
touchClose?: boolean,
/** 控制暗色背景的透明度 默认为190*/
opacity?: number;
}
/** 本类型仅供gui模块内部使用请勿在功能逻辑中使用 */
export class ViewParams {
/** 界面唯一标识 */
uuid: string = null!;
/** 预制路径 */
prefabPath: string = null!;
/** 界面配置 */
config: UIConfig = null!;
/** 传递给打开界面的参数 */
params: any = null!;
/** 窗口事件 */
@@ -57,4 +45,13 @@ export class ViewParams {
valid: boolean = true;
/** 界面根节点 */
node: Node = null!;
}
/** 弹框层回调对象定义(废弃) */
export interface PopViewParams extends UICallbacks {
/** 是否触摸背景关闭弹窗 */
touchClose?: boolean,
/** 控制暗色背景的透明度 默认为190*/
opacity?: number;
}

View File

@@ -14,50 +14,58 @@ const { ccclass } = _decorator;
@ccclass('DelegateComponent')
export class DelegateComponent extends Component {
/** 视图参数 */
viewParams: ViewParams = null!;
vp: ViewParams = null!;
/** 界面关闭回调 - 包括关闭动画播放完 */
onHide: Function = null!;
/** 窗口添加 */
add() {
// 触发窗口组件上添加到父节点后的事件
this.applyComponentsFunction(this.node, "onAdded", this.viewParams.params);
if (typeof this.viewParams.callbacks.onAdded === "function") {
this.viewParams.callbacks.onAdded(this.node, this.viewParams.params);
this.applyComponentsFunction(this.node, "onAdded", this.vp.params);
if (typeof this.vp.callbacks.onAdded === "function") {
this.vp.callbacks.onAdded(this.node, this.vp.params);
}
}
/** 删除节点该方法只能调用一次将会触发onBeforeRemoved回调 */
remove(isDestroy: boolean) {
if (this.viewParams.valid) {
// 触发窗口组件上移除之前事件
this.applyComponentsFunction(this.node, "onBeforeRemove", this.viewParams.params);
remove(isDestroy?: boolean) {
if (this.vp.valid) {
// 触发窗口移除舞台之前事件
this.applyComponentsFunction(this.node, "onBeforeRemove", this.vp.params);
// 通知外部对象窗口组件上移除之前的事件(关闭窗口前的关闭动画处理)
if (typeof this.viewParams.callbacks.onBeforeRemove === "function") {
this.viewParams.callbacks.onBeforeRemove(
if (typeof this.vp.callbacks.onBeforeRemove === "function") {
this.vp.callbacks.onBeforeRemove(
this.node,
() => {
this.removed(this.viewParams, isDestroy);
this.removed(this.vp, isDestroy);
});
}
else {
this.removed(this.viewParams, isDestroy);
this.removed(this.vp, isDestroy);
}
}
}
/** 窗口组件中触发移除事件与释放窗口对象 */
private removed(viewParams: ViewParams, isDestroy: boolean) {
viewParams.valid = false;
private removed(vp: ViewParams, isDestroy?: boolean) {
vp.valid = false;
if (typeof viewParams.callbacks.onRemoved === "function") {
viewParams.callbacks!.onRemoved(this.node, viewParams.params);
if (typeof vp.callbacks.onRemoved === "function") {
vp.callbacks!.onRemoved(this.node, vp.params);
}
// 界面移除舞台事件
this.onHide && this.onHide(vp);
if (isDestroy) {
// 释放界面显示对象
this.node.destroy();
// 释放界面相关资源
oops.res.release(viewParams.prefabPath);
oops.res.release(vp.config.prefab);
// oops.log.logView(`【界面管理】释放【${vp.config.prefab}】界面资源`);
}
else {
this.node.removeFromParent();
@@ -66,14 +74,8 @@ export class DelegateComponent extends Component {
onDestroy() {
// 触发窗口组件上窗口移除之后的事件
this.applyComponentsFunction(this.node, "onRemoved", this.viewParams.params);
// 通知外部对象窗口移除之后的事件
// if (typeof this.viewParams.callbacks!.onRemoved === "function") {
// this.viewParams.callbacks!.onRemoved(this.node, this.viewParams.params);
// }
this.viewParams = null!;
this.applyComponentsFunction(this.node, "onRemoved", this.vp.params);
this.vp = null!;
}
protected applyComponentsFunction(node: Node, funName: string, params: any) {

View File

@@ -23,54 +23,53 @@ type DialogParam = {
export class LayerDialog extends LayerPopUp {
/** 窗口调用参数队列 */
private params: Array<DialogParam> = [];
/** 当前窗口数据 */
private current!: ViewParams;
add(config: UIConfig, params?: any, callbacks?: UICallbacks): string {
this.black.enabled = true;
if (this.current && this.current.valid) {
let uuid = this.getUuid(config.prefab);
add(config: UIConfig, params?: any, callbacks?: UICallbacks) {
// 控制同一时间只能显示一个模式窗口
if (this.ui_nodes.size > 0) {
this.params.push({
config: config,
params: params,
callbacks: callbacks,
});
return uuid;
return;
}
return this.show(config, params, callbacks);
this.black.enabled = true;
this.show(config, params, callbacks);
}
/** 显示模式弹窗 */
private show(config: UIConfig, params?: any, callbacks?: UICallbacks): string {
let prefabPath = config.prefab
var uuid = this.getUuid(prefabPath);
var viewParams = this.ui_nodes.get(uuid);
if (viewParams == null) {
viewParams = new ViewParams();
viewParams.uuid = this.getUuid(prefabPath);
viewParams.prefabPath = prefabPath;
viewParams.valid = true;
this.ui_nodes.set(viewParams.uuid, viewParams);
var vp = this.ui_cache.get(config.prefab);
if (vp == null) {
vp = new ViewParams();
vp.config = config
vp.valid = true;
}
this.ui_nodes.set(vp.config.prefab, vp);
viewParams.callbacks = callbacks ?? {};
var onRemove_Source = viewParams.callbacks.onRemoved;
viewParams.callbacks.onRemoved = (node: Node | null, params: any) => {
vp.callbacks = callbacks ?? {};
var onRemove_Source = vp.callbacks.onRemoved;
vp.callbacks.onRemoved = (node: Node | null, params: any) => {
if (onRemove_Source) {
onRemove_Source(node, params);
}
setTimeout(this.next.bind(this), 0);
};
viewParams.params = params || {};
this.current = viewParams;
this.load(viewParams, config.bundle);
vp.params = params || {};
this.load(vp, config.bundle);
return uuid;
return config.prefab;
}
protected setBlackDisable() {
if (this.params.length == 0) this.black.enabled = false;
if (this.params.length == 0) {
this.black.enabled = false;
this.closeVacancyRemove();
this.closeMask()
}
}
private next() {

View File

@@ -50,8 +50,15 @@ export interface UIConfig {
layer: LayerType;
/** 预制资源相对路径 */
prefab: string;
/** 是否触摸非窗口区域关闭 */
vacancy?: boolean,
/** 是否打开窗口后显示背景遮罩 */
mask?: boolean;
/** 是否自动施放 */
destroy?: boolean;
}
/** 界面层级管理器 */
export class LayerManager {
/** 界面根节点 */
root!: Node;
@@ -260,16 +267,16 @@ export class LayerManager {
var result: Node = null!;
switch (config.layer) {
case LayerType.UI:
result = this.ui.getByPrefabPath(config.prefab);
result = this.ui.get(config.prefab);
break;
case LayerType.PopUp:
result = this.popup.getByPrefabPath(config.prefab);
result = this.popup.get(config.prefab);
break;
case LayerType.Dialog:
result = this.dialog.getByPrefabPath(config.prefab);
result = this.dialog.get(config.prefab);
break;
case LayerType.System:
result = this.system.getByPrefabPath(config.prefab);
result = this.system.get(config.prefab);
break;
}
return result;
@@ -282,7 +289,7 @@ export class LayerManager {
* @example
* oops.gui.remove(UIID.Loading);
*/
remove(uiId: number, isDestroy: boolean = true) {
remove(uiId: number, isDestroy?: boolean) {
var config = this.configs[uiId];
if (config == null) {
warn(`删除编号为【${uiId}】的界面失败,配置信息不存在`);
@@ -308,16 +315,39 @@ export class LayerManager {
/**
* 删除一个通过this框架添加进来的节点
* @param node 窗口节点
* @param isDestroy 移除后是否释放
* @param isDestroy 移除后是否释放资源
* @example
* oops.gui.removeByNode(cc.Node);
*/
removeByNode(node: Node, isDestroy: boolean = false) {
removeByNode(node: Node, isDestroy?: boolean) {
if (node instanceof Node) {
let comp = node.getComponent(DelegateComponent);
if (comp && comp.viewParams) {
// @ts-ignore 注:不对外使用
(node.parent as LayerUI).removeByUuid(comp.viewParams.uuid, isDestroy);
if (comp && comp.vp) {
// 释放显示的界面
if (node.parent) {
(node.parent as LayerUI).remove(comp.vp.config.prefab, isDestroy);
}
// 释放缓存中的界面
else if (isDestroy) {
switch (comp.vp.config.layer) {
case LayerType.UI:
// @ts-ignore 注:不对外使用
this.ui.removeCache(comp.vp.config.prefab);
break;
case LayerType.PopUp:
// @ts-ignore 注:不对外使用
this.popup.removeCache(comp.vp.config.prefab);
break;
case LayerType.Dialog:
// @ts-ignore 注:不对外使用
this.dialog.removeCache(comp.vp.config.prefab);
break;
case LayerType.System:
// @ts-ignore 注:不对外使用
this.system.removeCache(comp.vp.config.prefab);
break;
}
}
}
else {
warn(`当前删除的node不是通过界面管理器添加到舞台上`);

View File

@@ -4,16 +4,20 @@
* @LastEditTime: 2022-09-02 13:44:28
*/
import { BlockInputEvents, Layers } from "cc";
import { PopViewParams } from "./Defines";
import { BlockInputEvents, EventTouch, Layers, Node } from "cc";
import { ViewUtil } from "../../utils/ViewUtil";
import { ViewParams } from "./Defines";
import { UIConfig } from "./LayerManager";
import { LayerUI } from "./LayerUI";
/*
* 弹窗层,允许同时弹出多个窗口,弹框参数可以查看 PopViewParams
*/
const Mask: string = 'common/prefab/mask';
/* 弹窗层,允许同时弹出多个窗口 */
export class LayerPopUp extends LayerUI {
/** 触摸事件阻挡 */
protected black!: BlockInputEvents;
/** 半透明遮罩资源 */
protected mask!: Node;
constructor(name: string) {
super(name);
@@ -26,34 +30,95 @@ export class LayerPopUp extends LayerUI {
this.black.enabled = false;
}
/**
* 添加一个预制件节点到PopUp层容器中该方法将返回一个唯一uuid来标识该操作节点
* @param prefabPath 预制件路径
* @param params 传给组件onAdded、onRemoved方法的参数。
* @param popParams 弹出界面的设置定义详情见PopViewParams
*/
add(config: UIConfig, params: any, popParams?: PopViewParams): string {
protected showUi(vp: ViewParams) {
super.showUi(vp);
// 界面加载完成显示时,启动触摸非窗口区域关闭
this.openVacancyRemove(vp.config);
// 界面加载完成显示时,层级事件阻挡
this.black.enabled = true;
return super.add(config, params, popParams);
}
remove(prefabPath: string, isDestroy: boolean): void {
super.remove(prefabPath, isDestroy);
this.setBlackDisable();
}
protected removeByUuid(prefabPath: string, isDestroy: boolean): void {
super.removeByUuid(prefabPath, isDestroy);
protected onHide(vp: ViewParams) {
super.onHide(vp);
// 界面关闭后,关闭触摸事件阻挡、关闭触摸非窗口区域关闭、关闭遮罩
this.setBlackDisable();
}
/** 设置触摸事件阻挡 */
protected setBlackDisable() {
this.black.enabled = false;
// 所有弹窗关闭后,关闭事件阻挡功能
if (this.ui_nodes.size == 0) {
this.black.enabled = false;
}
this.closeVacancyRemove();
this.closeMask();
}
/** 关闭遮罩 */
protected closeMask() {
var flag = true;
for (var value of this.ui_nodes.values()) {
if (value.config.mask) {
flag = false;
break;
}
}
if (flag) {
this.mask.parent = null;
}
}
/** 启动触摸非窗口区域关闭 */
protected openVacancyRemove(config: UIConfig) {
if (!this.hasEventListener(Node.EventType.TOUCH_END, this.onTouchEnd, this)) {
this.on(Node.EventType.TOUCH_END, this.onTouchEnd, this);
}
// 背景半透明遮罩
if (this.mask == null) {
this.mask = ViewUtil.createPrefabNode(Mask);
}
if (config.mask) {
this.mask.parent = this;
this.mask.setSiblingIndex(0);
}
}
/** 关闭触摸非窗口区域关闭 */
protected closeVacancyRemove() {
var flag = true;
for (var value of this.ui_nodes.values()) {
if (value.config.vacancy) {
flag = false;
break;
}
}
if (flag && this.hasEventListener(Node.EventType.TOUCH_END, this.onTouchEnd, this)) {
this.off(Node.EventType.TOUCH_END, this.onTouchEnd, this);
}
}
private onTouchEnd(event: EventTouch) {
if (event.target === this) {
this.ui_nodes.forEach(vp => {
// 关闭已显示的界面
if (vp.valid && vp.config.vacancy) {
this.remove(vp.config.prefab, true);
}
});
}
}
clear(isDestroy: boolean) {
super.clear(isDestroy)
this.black.enabled = false;
this.active = false;
this.closeVacancyRemove();
this.closeMask();
}
}

View File

@@ -2,14 +2,11 @@
* UI基础层允许添加多个预制件节点
* add : 添加一个预制件节点到层容器中该方法将返回一个唯一uuid来标识该操作Node节点。
* delete : 根据uuid删除Node节点如果节点还在队列中也会被删除, 删除节点可以用gui.delete(node)或this.node.destroy()
* deleteByUuid : 根据预制路径删除,预制件在队列中也会被删除,如果该预制件存在多个也会一起删除
* get : 根据uuid获取Node节点如果节点不存在或者预制件还在队列中则返回null 。
* getByUuid : 根据预制件路径获取当前显示的该预制件的所有Node节点数组。
* get : 根据预制路径获取已打开界面的节点对象,如果节点不存在或者预制件在队列中则返回null
* has : 判断当前层是否包含 uuid或预制件路径对应的Node节点。
* find : 判断当前层是否包含 uuid或预制件路径对应的Node节点。
* clear : 清除所有Node节点队列当中未创建的任务也会被清除。
*/
import { error, instantiate, isValid, Node, Prefab, warn, Widget } from "cc";
import { error, instantiate, Node, Prefab, warn, Widget } from "cc";
import { oops } from "../../Oops";
import { UICallbacks, ViewParams } from "./Defines";
import { DelegateComponent } from "./DelegateComponent";
@@ -17,7 +14,7 @@ import { UIConfig } from "./LayerManager";
/** 界面层对象 */
export class LayerUI extends Node {
/** 界面节点集合 */
/** 显示界面节点集合 */
protected ui_nodes = new Map<string, ViewParams>();
/** 被移除的界面缓存数据 */
protected ui_cache = new Map<string, ViewParams>();
@@ -37,85 +34,81 @@ export class LayerUI extends Node {
widget.enabled = true;
}
/** 构造一个唯一标识UUID */
protected getUuid(prefabPath: string): string {
var uuid = `${this.name}_${prefabPath}`;
return uuid.replace(/\//g, "_");
}
/**
* 添加一个预制件节点到层容器中,该方法将返回一个唯一`uuid`来标识该操作节点
* @param prefabPath 预制件路径
* @param params 自定义参数
* @param callbacks 回调函数对象,可选
* @returns ture为成功,false为失败
*/
add(config: UIConfig, params?: any, callbacks?: UICallbacks): string {
let prefabPath = config.prefab;
var uuid = this.getUuid(prefabPath);
var viewParams = this.ui_nodes.get(uuid);
if (viewParams && viewParams.valid) {
warn(`路径为【${prefabPath}】的预制重复加载`);
return "";
add(config: UIConfig, params?: any, callbacks?: UICallbacks) {
if (this.ui_nodes.has(config.prefab)) {
warn(`路径为【${config.prefab}】的预制重复加载`);
return;
}
if (viewParams == null) {
viewParams = new ViewParams();
viewParams.uuid = uuid;
viewParams.prefabPath = prefabPath;
this.ui_nodes.set(viewParams.uuid, viewParams);
// 检查缓存中是否存界面
var vp = this.ui_cache.get(config.prefab);
if (vp == null) {
vp = new ViewParams();
vp.config = config;
}
this.ui_nodes.set(config.prefab, vp);
viewParams.params = params ?? {};
viewParams.callbacks = callbacks ?? {};
viewParams.valid = true;
vp.params = params ?? {};
vp.callbacks = callbacks ?? {};
vp.valid = true;
this.load(viewParams, config.bundle)
return uuid;
this.load(vp, config.bundle)
}
/**
* 加载界面资源
* @param viewParams 显示参数
* @param vp 显示参数
* @param bundle 远程资源包名,如果为空就是默认本地资源包
*/
protected load(viewParams: ViewParams, bundle?: string) {
var vp: ViewParams = this.ui_nodes.get(viewParams.uuid)!;
protected load(vp: ViewParams, bundle?: string) {
if (vp && vp.node) {
this.createNode(vp);
this.showUi(vp);
}
else {
// 优先加载配置的指定资源包中资源,如果没配置则加载默认资源包资源
bundle = bundle || oops.res.defaultBundleName;
oops.res.load(bundle, viewParams.prefabPath, (err: Error | null, res: Prefab) => {
oops.res.load(bundle, vp.config.prefab, (err: Error | null, res: Prefab) => {
if (err) {
this.ui_nodes.delete(viewParams.uuid);
error(`路径为【${viewParams.prefabPath}】的预制加载失败`);
this.ui_nodes.delete(vp.config.prefab);
error(`路径为【${vp.config.prefab}】的预制加载失败`);
return;
}
let childNode: Node = instantiate(res);
viewParams.node = childNode;
vp.node = childNode;
let comp = childNode.addComponent(DelegateComponent);
comp.viewParams = viewParams;
comp.vp = vp;
comp.onHide = this.onHide.bind(this);
this.createNode(viewParams);
this.showUi(vp);
});
}
}
protected onHide(vp: ViewParams) {
this.ui_nodes.delete(vp.config.prefab);
}
/**
* 创建界面节点
* @param viewParams 视图参数
* @param vp 视图参数
*/
protected createNode(viewParams: ViewParams) {
viewParams.valid = true;
let comp = viewParams.node.getComponent(DelegateComponent)!;
protected showUi(vp: ViewParams) {
// 触发窗口添加事件
let comp = vp.node.getComponent(DelegateComponent)!;
comp.add();
viewParams.node.parent = this;
vp.node.parent = this;
// 标记界面为使用状态
vp.valid = true;
}
/**
@@ -123,55 +116,40 @@ export class LayerUI extends Node {
* @param prefabPath 预制路径
* @param isDestroy 移除后是否释放
*/
remove(prefabPath: string, isDestroy: boolean): void {
// 验证是否删除后台缓存界面
if (isDestroy) this.removeCache(prefabPath);
remove(prefabPath: string, isDestroy?: boolean): void {
var release = true;
// 默认不配置为关闭界面释放资源
if (isDestroy == undefined) release = true;
// 界面移出舞台
let children = this.__nodes();
for (let i = 0; i < children.length; i++) {
let viewParams = children[i].viewParams;
if (viewParams.prefabPath === prefabPath) {
if (isDestroy) {
// 直接释放界面
this.ui_nodes.delete(viewParams.uuid);
}
else {
// 不释放界面,缓存起来待下次使用
this.ui_cache.set(viewParams.prefabPath, viewParams);
}
children[i].remove(isDestroy);
viewParams.valid = false;
var vp = this.ui_nodes.get(prefabPath);
if (vp) {
// 优先使用参数中控制的释放条件,如果未传递参数则用配置中的释放条件
if (isDestroy == undefined && vp.config.destroy != undefined) {
release = vp.config.destroy;
}
}
}
/**
* 根据唯一标识删除节点,如果节点还在队列中也会被删除
* @param uuid 唯一标识
*/
protected removeByUuid(uuid: string, isDestroy: boolean): void {
var viewParams = this.ui_nodes.get(uuid);
if (viewParams) {
if (isDestroy)
this.ui_nodes.delete(viewParams.uuid);
// 不释放界面,缓存起来待下次使用
if (!release) {
this.ui_cache.set(vp.config.prefab, vp);
}
var childNode = viewParams.node;
var childNode = vp.node;
var comp = childNode.getComponent(DelegateComponent)!;
comp.remove(isDestroy);
comp.remove(release);
}
// 验证是否删除后台缓存界面
if (release) this.removeCache(prefabPath);
}
/**
* 删除缓存的界面,当缓存界面被移除舞台时,可通过此方法删除缓存界面
*/
/** 删除缓存的界面,当缓存界面被移除舞台时,可通过此方法删除缓存界面 */
private removeCache(prefabPath: string) {
let viewParams = this.ui_cache.get(prefabPath);
if (viewParams) {
this.ui_nodes.delete(viewParams.uuid);
let vp = this.ui_cache.get(prefabPath);
if (vp) {
this.ui_nodes.delete(vp.config.prefab);
this.ui_cache.delete(prefabPath);
var childNode = viewParams.node;
var childNode = vp.node;
childNode.destroy();
}
}
@@ -180,80 +158,19 @@ export class LayerUI extends Node {
* 根据预制路径获取已打开界面的节点对象
* @param prefabPath 预制路径
*/
getByPrefabPath(prefabPath: string): Node {
var uuid = this.getUuid(prefabPath);
return this.getByUuid(uuid);
}
/**
* 根据唯一标识获取节点如果节点不存在或者还在队列中则返回null
* @param uuid 唯一标识
*/
getByUuid(uuid: string): Node {
let children = this.__nodes();
for (let comp of children) {
if (comp.viewParams && comp.viewParams.uuid === uuid) {
return comp.node;
}
}
get(prefabPath: string): Node {
var vp = this.ui_nodes.get(prefabPath);
if (vp)
return vp.node;
return null!;
}
/**
* 根据预制件路径获取当前显示的该预制件的所有Node节点数组
* @param prefabPath
*/
get(prefabPath: string): Array<Node> {
let arr: Array<Node> = [];
let children = this.__nodes();
for (let comp of children) {
if (comp.viewParams.prefabPath === prefabPath) {
arr.push(comp.node);
}
}
return arr;
}
/**
* 判断当前层是否包含 uuid或预制件路径对应的Node节点
* @param prefabPathOrUUID 预制件路径或者UUID
* @param prefabPath 预制件路径或者UUID
*/
has(prefabPathOrUUID: string): boolean {
let children = this.__nodes();
for (let comp of children) {
if (comp.viewParams.uuid === prefabPathOrUUID || comp.viewParams.prefabPath === prefabPathOrUUID) {
return true;
}
}
return false;
}
/**
* 获取当前层包含指定正则匹配的Node节点。
* @param prefabPathReg 匹配预制件路径的正则表达式对象
*/
find(prefabPathReg: RegExp): Node[] {
let arr: Node[] = [];
let children = this.__nodes();
for (let comp of children) {
if (prefabPathReg.test(comp.viewParams.prefabPath)) {
arr.push(comp.node);
}
}
return arr;
}
/** 获取当前层所有窗口事件触发组件 */
protected __nodes(): Array<DelegateComponent> {
let result: Array<DelegateComponent> = [];
let children = this.children;
for (let i = 0; i < children.length; i++) {
let comp = children[i].getComponent(DelegateComponent);
if (comp && comp.viewParams && comp.viewParams.valid && isValid(comp)) {
result.push(comp);
}
}
return result;
has(prefabPath: string): boolean {
return this.ui_nodes.has(prefabPath);
}
/**
@@ -263,7 +180,7 @@ export class LayerUI extends Node {
clear(isDestroy: boolean): void {
// 清除所有显示的界面
this.ui_nodes.forEach((value: ViewParams, key: string) => {
this.removeByUuid(value.uuid, isDestroy);
this.remove(value.config.prefab, isDestroy);
value.valid = false;
});
this.ui_nodes.clear();

View File

@@ -5,6 +5,7 @@
* @LastEditTime: 2022-03-25 23:43:25
*/
import { Material } from 'cc';
import { Color, Component, macro, MeshRenderer, Node, renderer, v2, Vec2, Vec3, _decorator } from 'cc';
const { ccclass, property } = _decorator;
@@ -32,7 +33,7 @@ export class NavLine extends Component {
xEuler = true;
/* 材质 */
private mat: renderer.MaterialInstance = null!;
private mat: Material | renderer.MaterialInstance | null = null!;
/* 导航线是否启动 */
private inited = false;
@@ -56,7 +57,7 @@ export class NavLine extends Component {
this.mesh.node.active = true;
this.frame = 0;
this.inited = true;
this.mat.setProperty("mainColor", this.color);
this.mat?.setProperty("mainColor", this.color);
this.start_pos.set(this.player.worldPosition);
this.target_pos.set(pos);
@@ -76,7 +77,7 @@ export class NavLine extends Component {
this.node.setScale(this.node.scale.x, this.node.scale.y, this.distance);
this.node.setWorldPosition(this.player.worldPosition);
this.tOffset.y = this.distance * this.density;
this.mat.setProperty("tilingOffset", this.tOffset);
this.mat?.setProperty("tilingOffset", this.tOffset);
if (this.xEuler) this.rotation(this.start_pos, this.target_pos);
}

View File

@@ -60,7 +60,7 @@ export class ModuleUtil {
* @param uiId 界面资源编号
* @param isDestroy 是否释放界面缓存
*/
public static removeView(ent: ecs.Entity, ctor: CompType<ecs.IComp>, uiId: number, isDestroy: boolean = true) {
public static removeView(ent: ecs.Entity, ctor: CompType<ecs.IComp>, uiId: number, isDestroy?: boolean) {
ent.remove(ctor);
oops.gui.remove(uiId, isDestroy);
}