UI模块
目录
我们接之前【资源模块】,现在继续使用AI帮我们写一个【UI管理器】。
前言
UI管理器,主要提供UI界面的创建、显示、隐藏、销毁。
UI管理器是我们游戏中很常用的功能,比如:登录UI、大厅UI、游戏中的人物背包UI、游戏设置UI、掉线时出现的警告UI等等。
我把游戏中的UI简单分为2种:一种是场景UI、一种是窗口UI,我喜欢称呼场景UI为大UI,窗口UI为小UI。比如:我们把游戏看成一个 web 网站,其中【用户登录页面】就等于【登录UI】也就是场景UI,如果登录失败时出现的【错误提示框】就等于【提示UI】也就是窗口UI。
小白必读:UI管理器的用处?
答:UI管理器能方便的统一管理我们游戏中各种UI,哪些UI需要常驻保留,提高复用、哪些UI需要用后销毁,减少开销。也能让我们在显示UI时赋予动画效果等等。在我们的框架中UI的类型都是预制体,符合我们【单场景+多预制体】的开发模式。
一、新建UIMgr.ts
我们继续在Core分包目录下的Scripts\Managers目录新建UIMgr.ts
二、提问AI
注意:现在我们需要结合ResMgr.ts的资源加载读取,来写代码。
1、点击提问区的 + 号
2、选择ResMgr.ts
3、输入问题
结合ResMgr.ts,用ccc 3.8.x 内置 API 帮我们写一个UIMgr.tsUI管理器,实现:
1、UI界面的创建、显示、隐藏、销毁
2、创建时可以根据参数设置UI是否缓存,提高复用
3、UI属于预制体类型
4、在 constructor 中 使用 director.once的Director.EVENT_AFTER_SCENE_LAUNCH事件执行init
5、在init中获取场景Canvas根节点作为UI父节点,但在编辑器模式下不执行
5、参考ResMgr单例方式,并导出
三、优化修改
从上图种我们看到有几个地方需要修改:
1、我们的UI是预制体,并且存放于各个分包里,而不是单独的 ui 分包
2、prefabPath 参数应该包含分包名称
3、showUI里应该加一个如果没有获取到缓存就直接使用createUI新建
4、注释说明不完整
四、最终版本
import { Node, Prefab, instantiate, director, isValid, Director } from 'cc';
import { resMgr } from './ResMgr';
import { EDITOR } from 'cc/env';
/**
* UI管理器
* 用于UI界面的创建、显示、隐藏、销毁
*/
export class UIMgr {
private uiRoot: Node | null = null;
private uiCache: Map<string, Node> = new Map();
/** 单例实例 */
public static readonly instance: UIMgr = new UIMgr();
// 私有构造函数,防止外部实例化
private constructor() {
director.once(Director.EVENT_AFTER_SCENE_LAUNCH, this.init, this);
}
/**
* 初始化UI管理器
* 在非编辑器模式下,获取场景中的Canvas节点作为UI的父节点
*/
private init() {
if (!EDITOR) {
this.uiRoot = director.getScene().getChildByName('Canvas')!;
}
}
/**
* 创建UI界面
* @param {string} prefabPath - 预制体路径,格式为 "bundleName/prefabPath"
* @param {boolean} cache - 是否缓存UI节点
* @param {Function} callback - 创建完成时的回调函数
*/
public createUI(prefabPath: string, cache: boolean = true, callback: (err: Error | null, uiNode: Node | null) => void) {
if (this.uiCache.has(prefabPath)) {
callback(null, this.uiCache.get(prefabPath)!);
return;
}
const [bundleName, path] = prefabPath.split('/', 2);
resMgr.loadAsset(bundleName, path, Prefab, (err, prefab) => {
if (err) {
callback(err, null);
return;
}
const uiNode = instantiate(prefab);
if (this.uiRoot && isValid(this.uiRoot)) {
this.uiRoot.addChild(uiNode);
}
if (cache) {
this.uiCache.set(prefabPath, uiNode);
}
callback(null, uiNode);
});
}
/**
* 显示UI界面
* 如果UI未缓存,则创建新的UI
* @param {string} prefabPath - 预制体路径
*/
public showUI(prefabPath: string) {
const uiNode = this.uiCache.get(prefabPath);
if (uiNode && isValid(uiNode)) {
uiNode.active = true;
} else {
this.createUI(prefabPath, true, (err, newUiNode) => {
if (!err && newUiNode) {
newUiNode.active = true;
}
});
}
}
/**
* 隐藏UI界面
* @param {string} prefabPath - 预制体路径
*/
public hideUI(prefabPath: string) {
const uiNode = this.uiCache.get(prefabPath);
if (uiNode && isValid(uiNode)) {
uiNode.active = false;
}
}
/**
* 销毁UI界面
* @param {string} prefabPath - 预制体路径
*/
public destroyUI(prefabPath: string) {
const uiNode = this.uiCache.get(prefabPath);
if (uiNode && isValid(uiNode)) {
uiNode.destroy();
this.uiCache.delete(prefabPath);
}
}
}
/** 导出实例 */
export const uiMgr = UIMgr.instance;
五、总结
这里呢我们没有区分场景UI和窗口UI,也没有设置UI的层级,只是简单的通过创建、显示、隐藏、销毁达到管理UI的目的,在以后的实际开发中我们会对UI管理器进行扩展。
作者:ccs2d.com 创建时间:2024-09-30 04:44
最后编辑:ccs2d.com 更新时间:2024-10-06 09:43
最后编辑:ccs2d.com 更新时间:2024-10-06 09:43