网站设计与建设考试,网站手机版跳转代码,查询注册过哪些网站,最新网络营销方式有哪些游戏开发实现简易实用的ui框架 本文使用cocos引擎实现#xff0c;框架代码本质上不依赖某一个引擎#xff0c;稍作修改也能作为其他引擎的实现 1.1 UI管理框架的核心需求剖析 分层与类型管理 对不同类型UI需要进行分层管理。不同层级的UI需要有不同的父节点#xff0c;保证渲…游戏开发实现简易实用的ui框架 本文使用cocos引擎实现框架代码本质上不依赖某一个引擎稍作修改也能作为其他引擎的实现 1.1 UI管理框架的核心需求剖析 分层与类型管理 对不同类型UI需要进行分层管理。不同层级的UI需要有不同的父节点保证渲染顺序和交互优先级。 资源管理与预加载 支持动态加载UI资源并缓存已加载的资源。提供预加载功能提前加载高频使用的UI。 实例化与复用 管理UI实例的创建和销毁避免重复创建。通过缓存机制复用UI实例减少性能开销。 显示与隐藏管理 提供便捷的API控制UI的显示与隐藏。能自动控制UI层级。 事件与参数传递 支持通过参数初始化UI方便UI组件根据业务逻辑动态变化。 1.2 探讨UI层级的问题 在做UI管理的时候层级关系是一个常见的问题特别是在动态加载时由于设计不当或忽视一些细节从而导致层级混乱、显示错误或者UI交互问题。 毛毛虫认为解决这个问题的一个方式就是进行UI分类管理只要根据UI的类型对其层级加以区分不同类型的UI展示具有不同的特性。 在本次的设计中将UI区分为四个UI层全屏视图、弹框、常驻UI、提示视图。 全屏视图是优先级最低的UI显示在所有视图之下同一时间只会存在一个全屏视图。 常驻UI通常是底部或顶部的UI多用于全屏视图的切换优先级只比全屏视图高。 弹框是游戏中最多的UI具有较高的优先级同时可以出现多个越晚出现的弹框层级越高。 提示视图是优先级最高的UI提示视图不是指提示框提示框应该被归类为弹框常见的提示视图有加载界面、过场动画、网络故障提示等。多数情况提示视图不会同时出现多个如果存在多个越晚出现的层级应当越高。 1.3 UI基类的设计和自定义生命周期的封装
基类模板
export default abstract class BaseView extends cc.Component implements IBaseView{UIType: UI_TYPE;private _params: any;get params(){return this._params;}set params(v) {this._params v;}onLoad(){//#region 公共事件//#endregionthis.OnMountEnd();}/**挂载后事件作OnLoad使用 */protected abstract OnMountEnd();protected onEnable(): void {this.ShowUI(this.params);}abstract ShowUI(params: any);HideUI() {//#region 公共事件//#endregionthis.node.active false;}
}
export abstract class FullView extends BaseView{UIType: UI_TYPE UI_TYPE.FULL;
}
export abstract class PopView extends BaseView{UIType: UI_TYPE UI_TYPE.POP;
}
export abstract class TipView extends BaseView{UIType: UI_TYPE UI_TYPE.FULL;
}
export abstract class ResidentView extends BaseView{UIType: UI_TYPE UI_TYPE.RESIDENT;
}
export enum UI_TYPE{/**全屏视图 */FULL,/**弹出视图 */POP,/**提示视图 */TIP,/**常驻视图 */RESIDENT
}
interface IBaseView{UIType: UI_TYPE;/**显示UI事件 */ShowUI(params: any);
}基类设计的特点与目的 通用性 BaseView 提供了一个统一的结构所有具体的 UI 类都继承自此类IBaseView 给予 UI 类一些行为约束。 生命周期的封装 使用 OnMountEnd 替代了 onLoad将公共逻辑与具体实现分离。确保了在 onLoad 执行一些通用逻辑如资源加载、事件注册后具体的子类可以通过 OnMountEnd 来完成特定的初始化工作。ShowUIUI 的初始化和展示逻辑在 UI 被展示时调用可以根据传入的参数动态初始化视图内容提升灵活性可以理解为可以传参的激活事件。HideUI为视图的销毁提供一个统一的入口避免直接调用 node.active false 导致遗漏清理逻辑为后续的扩展如内存回收、动画关闭等提供了统一的触发点 UI 类型的标记 基于 UI_TYPE 枚举定义了四种 UI 类型并通过抽象类FullView、PopView 等进行进一步的封装。子类通过继承对应的抽象类自动绑定 UI 类型减少重复代码。 1.4 UI管理器的封装
UI管理器模板
import BaseView, { UI_TYPE } from ./BaseView;
const UIPath: string prefab/UI/;
export default class UIManager {private isInited: boolean false;private static instance: UIManager null;private FullParentNode: cc.Node null;private PopParentNode: cc.Node null;private TipParentNode: cc.Node null;private ResidentParentNode: cc.Node null;public static get inst() {if (this.instance null) {this.instance new UIManager();}return this.instance;}public initUIManager(fullParentNode: cc.Node,popParentNode: cc.Node,tipParentNode: cc.Node null,residentParentNode: cc.Node null) {this.FullParentNode fullParentNode;this.PopParentNode popParentNode;this.TipParentNode tipParentNode;this.ResidentParentNode residentParentNode;}private UIcache: { [key: string]: BaseView } {};private onView: BaseView null;public ShowUI(ViewClass: string, params?) {let view: BaseView this.UIcache[ViewClass];if (view null) {this.instacePrefab(ViewClass, true, params)return;}if (view.node.active) {console.error(请勿重复加载);return;}view.params params;this.Mount(view);view.node.active true;}public HideUI(ViewClass: string) {let view: BaseView this.UIcache[ViewClass];view view.HideUI();}public preloadUI(uiViews: string[]) {if (this.isInited) {return;}this.isInited true;uiViews.forEach(uiView this.instacePrefab(uiView));}private instacePrefab(UIName: string, isShow: boolean false, params?: any) {if (this.UIcache[UIName]) {return;}cc.resources.load(UIPath UIName, cc.Prefab, (err, assert) {if (err) {console.error(没有${UIName}页面路径信息:${UIPath UIName});return;}let uiNode: cc.Node cc.instantiate(assert as cc.Prefab);let uiView: BaseView uiNode.getComponent(BaseView);if (uiView null) {console.error(${UIName}没有挂载脚本路径信息:${UIPath UIName});return;}this.UIcache[assert.name] uiView;uiView.params params;this.Mount(uiView);uiNode.active isShow;})}private Mount(view: BaseView) {switch (view.UIType) {case UI_TYPE.FULL:this.onView this.onView.HideUI();this.onView view;view.node.parent this.FullParentNode;break;case UI_TYPE.POP:view.node.setSiblingIndex(999);view.node.parent this.PopParentNode;break;case UI_TYPE.TIP:view.node.setSiblingIndex(999);view.node.parent this.TipParentNode;break;case UI_TYPE.RESIDENT:view.node.parent this.ResidentParentNode;break;}}public hideResidentNode() {this.ResidentParentNode.children.forEach(nod nod.active false);}public HideAll() {Object.keys(this.UIcache).forEach(key {let view: BaseView this.UIcache[key];if (view.node.active) {view.HideUI();}})}public getView(ViewClass: new () BaseView): BaseView {let view: BaseView this.UIcache[ViewClass.name];if (view null) {console.error(页面${ViewClass.name}不存在);return null;}return view;}
}UIManager 是整个项目的 UI 管理框架核心模块主要用于加载、显示、隐藏以及管理 UI 层级,通过分层管理和缓存机制使 UI 管理更为结构化、高效化 单例模式 get inst通过单例模式实现全局唯一实例避免多个实例造成管理混乱。但大型项目最好是实现一个 IOC 容器管理避免实例滥用 UI显示管理 ShowUI方法用于控制 UI 的激活记录 UI 视图的初始化参数节点生命周期onLoad的运行时机在第一次挂载时而节点实例如果默认是激活状态会出现自动执行onEnable从而导致参数未记录就执行 UI 视图的ShowUI事件故参数记录应当在挂载之前当然也可以通过手动将节点设置为非激活状态如果有需求在节点挂载前执行一些逻辑也可以添加在下面代码挂载前事件标记的位置 //#region 挂载前事件
//#endregion
view.params params;
this.Mount(view);
view.node.active true;UI挂载管理 Mount方法控制节点的挂载使不同类型的 UI 视图判断自己的逻辑如全屏视图需要关闭上一个全屏视图并记录弹出视图需要修改节点索引 预加载 preloadUI方法实现 UI 的预加载可以将常使用的视图提前加载优化 UI 速度 其他 通常情况下不建议使用getView获取并持有视图脚本一切行为应该趋向于中心管理UI 的隐藏事件尽可能的使用 UI 类的HideUI方法而非 UIManager 的HideUI方法UI 视图名称可以使用枚举记录而并未字符串根据不同的语言特性部分语言可以直接使用class类因为 cocos 构建后类名会被编译成简单的字母不能和预制体统一名称故该案例使用的字符串 1.5 使用示例
实现示例
ccclass
export default class AMoudleView extends PopView {protected OnMountEnd() {//进行节点获取、适配、事件注册等操作}ShowUI(params: {具体属性}) {//UI初始化逻辑}HideUI(): void {//在此实现私有隐藏事件非特殊需求尽量不要写在 super.HideUI() 之后super.HideUI();}
}UI 调用逻辑
//通过 UI 的中心管理器 UIManager 显示视图
UIManager.inst.ShowUI(ViewName.AModuleView, { 具体参数 });2.1 结语
对于微型项目毛毛虫不建议专门搭建一个框架一方面框架的搭建无可避免的容易增加代码量另一方面框架的设计需要对生命周期有较深理解否则容易出现时序性的问题。