当前位置: 首页 > news >正文

游戏开发学习记录

初始化只是第一次实例化的时候调用,show和unshow是打开界面和关闭界面的时候,会多次调用
在一个脚本里面show是每一次打开界面的时候需要做的事情,而Init是初始化。

UIMgr里面的数据结构:

为什么我要先从数据结构入手呢?因为程序 = 数据结构 + 算法!!!!!!

UIMgr(UI 管理器),用于管理游戏中打开、关闭、缓存 UI 页面,属于典型的 MVC(Model-View-Controller)架构中的 View 管理层

List<PageInfo> m_Ctrls —— 当前正在显示的页面列表

  • 类型:List<PageInfo>

  • 用途:保存当前正在显示(激活)的页面。

  • 特性:打开时添加,关闭时移除。

 List<PageInfo> m_Caches —— 已经关闭但缓存的页面

  • 类型:List<PageInfo>

  • 用途:用作“对象池”,防止 UI 页面重复加载。

  • 特性:关闭后放入缓存,下次打开优先从缓存中取。

UIMgr(UI管理器)

├── PageInfo  // 每个页面的信息,包含 Ctrl 和 View
│   ├── m_PageType : EPageType      // 页面枚举
│   ├── m_Ctrl : BaseCtrl           // 控制器逻辑
│   ├── m_View : BaseView           // UI 视图
│   ├── m_IsOpen : bool             // 当前是否打开

├── BaseCtrl(控制器)
│   ├── Init() / Show() / UnShow()  // 控制逻辑
│   ├── m_PageInfo : PageInfo

├── BaseView(UI显示层)
│   ├── Init() / Show() / UnShow()  // 视觉表现
│   ├── m_PageInfo : PageInfo
│   ├── m_Panel : UIPanel           // FairyGUI UI根

核心算法流程:

一.打开页面(OpenPage(EPageType type)

输入:EPageType(页面类型枚举)

算法流程:
1. 检查是否已经在打开中(m_Ctrls 中查找)
2. 如果缓存中有(m_Caches 中查找),直接复用(缓存指的是“已经关闭但没有销毁的页面实例”,用于复用,避免重复创建,提高性能。
3. 如果没有,就创建新页面
- 加载资源(从路径映射表中查路径)
- 挂载 PageInfo、BaseCtrl、BaseView、UIPanel
- 初始化 Ctrl 与 View

4. 添加到当前页面列表 m_Ctrls
5. 显示 Ctrl 和 View


二.关闭页面 closePage()

        

输入:可以是 EPageType / PageInfo / BaseCtrl / BaseView

算法流程:
1. 设置页面状态为关闭
2. 调用 Ctrl 和 View 的隐藏方法(带或不带动画)
3. 从 m_Ctrls 中移除
4. 添加到 m_Caches(复用池)
5. 广播事件通知 UI 被关闭

三.重新刷新页面 RefreshCurPage()

1. 取出栈顶页面(最后一个 m_Ctrls)
2. 关闭它
3. 再打开它(重新加载或从缓存中恢复)

四.同时关闭并打开新页面(CloseAndOpenPage)

1. 先关闭传入的旧页面(PageInfo 或 BaseCtrl)
2. 再打开新的页面

五.查找指定页面信息

PageInfo GetPageInfo(EPageType type)
遍历 m_Ctrls,找到匹配页面类型的 PageInfo



eg:

打开背包页面时,OpenPage(EPageType.BagPage) 会:

  1. 检查当前 UI 中是否已经有 BagPage

  2. 没有则加载资源,例如 "UI/BagPanel"

  3. 实例化组件,挂载脚本

  4. 添加到 m_Ctrls 列表

  5. 展示 UI 视图

关闭时会反过来处理。

C#基础语法
语法点示例建议学习关键词
类继承: Singleton<UIMgr>泛型继承、泛型类
构造函数保护protected override void OnInit()虚方法、重写
泛型方法GetPageCtrl<T>() where T : BaseCtrl泛型约束
集合操作List<PageInfo>.Add/Remove集合遍历、倒序遍历
条件判断if / else / return分支语句
循环for / foreach倒序删除元素的写法
类型转换as PlayerEvt, as T类型安全转换
组件操作AddComponent<>(), GetComponent<>()Unity / FairyGUI 组件获取
字典操作TryGetValue()Dictionary 用法
日志打印MyLogger.Info()打印调试工具类
枚举EPageType枚举类型使用

基础语法回顾

什么是泛型?
泛型(Generic)是为类或方法指定“类型参数的一种机制。可以让你的代码更通用、可复用,而且类型安全

泛型类型示例:

public class Box<T>
{public T Content;public void Print(){Console.WriteLine(Content);}
}

使用方法:

Box<string> box1 = new Box<string>();
box1.Content = "Hello";Box<int> box2 = new Box<int>();
box2.Content = 123;

泛型方法示例:

public class Printer
{public void Print<T>(T value){Console.WriteLine(value);}
}

调用方式:

Printer p = new Printer();
p.Print("文字");
p.Print(100);

泛型约束:

public T GetPageCtrl<T>(EPageType ePageType) where T : BaseCtrl

这表示 T 必须继承自 BaseCtrl,否则编译报错。这叫泛型约束

List倒序删除元素
为什么要倒序删除?
因为如果你正序删除索引会移动容易漏删或报错。

如下写法:

for (int i = list.Count - 1; i >= 0; i--)
{if (list[i] == 条件){list.RemoveAt(i);}
}


C# override 和 base 的区别

override是重写父类方法

public class Base
{public virtual void Speak(){Console.WriteLine("Base speaking");}
}public class Child : Base
{public override void Speak(){Console.WriteLine("Child speaking");}
}


base是调用父类方法

public override void Speak()
{base.Speak();  // 先调用父类逻辑Console.WriteLine("Child speaking");
}

你可以理解为:

  • override: 我要覆盖父类行为

  • base: 我要在子类中继续使用父类行为

什么是MVC架构

MVC是什么?

MVC 全称:Model - View - Controller
是一种软件架构模式,用于分离数据、界面与逻辑提高可维护性与模块化

如我的UIMgr里面的MVC架构:

组件作用示例类
Model数据DataMgr, ItemData
View界面显示BaseView, UIPanel
Controller控制逻辑BaseCtrl
MVC示意图:


  • Controller 连接用户输入与业务逻辑

  • View 专注展示 UI,不处理逻辑

  • Model 是纯数据(如道具表、角色数据)

UIPanel是什么?

FairyGUI 中,UIPanel挂在 GameObject 上的 UI 容器组件,用于将 FGUI 的 UI 显示在 Unity 场景中。

用法说明:

UIPanel panel = go.GetComponent<UIPanel>();
panel.ui = UIPackage.CreateObject("包名", "组件名") as GComponent;
  • UIPanel.ui:是一个 FGUI 的 GComponent,就是 UI 根节点

  • 每个页面视图(BaseView)都挂在这个 panel 上操作

GetComponent<T>()如何用?

Unity 中常用来获取挂载在 GameObject 上的组件脚本

示例:

// 获取自身挂载的 BoxCollider
BoxCollider box = gameObject.GetComponent<BoxCollider>();// 获取子物体上挂载的 BaseView
BaseView view = transform.Find("Child").GetComponent<BaseView>();


常见错误:

// 错误:可能 GameObject 上没有这个组件
var view = go.GetComponent<BaseView>();
if (view == null) Debug.Log("没有找到组件!");


 如何异步加载UI?

Unity 中 UI 面板如果太大,推荐异步加载资源文件,以防卡顿。


简单异步加载方式(基于 Addressables 或 Resources

IEnumerator LoadUI(string path, Action<GameObject> callback)
{ResourceRequest request = Resources.LoadAsync<GameObject>(path);yield return request;GameObject obj = GameObject.Instantiate(request.asset as GameObject);callback?.Invoke(obj);
}

调用方式:

StartCoroutine(LoadUI("UIPrefab/Bag", (ui) => {// 初始化逻辑
}));

总结
关键词用途重点
泛型类与方法复用,带类型限制T, where T : BaseCtrl
List 倒序删除避免删除错位for (i = Count - 1; i--)
override/base子类覆盖/调用父类方法多态
MVC分离逻辑/界面/数据架构思想
UIPanelFairyGUI 与 Unity 桥梁ui = GComponent
GetComponent获取组件类型匹配注意空检查
异步加载防止 UI 卡顿Resources.LoadAsync, Addressables

缓存 
缓存指的是“已经关闭但没有销毁的页面实例”,用于复用,避免重复创建,提高性能。

List<PageInfo> m_Caches;

保留在内存中,放入缓存列表中,等下次打开时直接复用。

原因说明
🚀 提高性能打开/关闭页面频繁,如果每次都加载资源、实例化,会卡顿、浪费性能
🧠 减少 GC避免频繁创建销毁对象带来的垃圾回收
⏱️ 加快响应速度从缓存中复用 UI 页面几乎是瞬间完成的

缓存逻辑是如何运作的?

1.打开页面时 
OpenPage(EPageType type)

// 先检查缓存列表
PageInfo pageInfo = GetCachePage(type);
if (pageInfo != null)
{// 从缓存恢复m_Caches.Remove(pageInfo);m_Ctrls.Add(pageInfo);pageInfo.m_Ctrl.Show();pageInfo.m_View.Show();
}

2.关闭页面时 Close Page(Page InfopageInfo):

pageInfo.m_IsOpen = false;// 隐藏,但不销毁
pageInfo.m_Ctrl.UnShow();
pageInfo.m_View.UnShow();// 从显示列表中移除
m_Ctrls.Remove(pageInfo);// 加入缓存列表
m_Caches.Add(pageInfo);

示意图:页面状态转换



类似现实中:

想象你是个餐馆老板:

  • 顾客来了:你先看看有没有空桌子(缓存)

  • 没有就新摆一张桌子(创建新的页面)

  • 顾客走了,你不收桌子,只是让它暂时闲置,等下个顾客再来用(放入缓存)


缓存的注意点:

  • UI 页面状态要正确重置(避免残留上次数据)

  • 如果页面太多,可能要设计LRU缓存策略(如保留最近 3 个页面,其余销毁)

  • 缓存列表不能太大,否则内存占用也会增加

    缓存是“已关闭但未销毁的页面”,用于下次快速复用,提高性能、减少加载。

http://www.dtcms.com/a/270492.html

相关文章:

  • 基于Flask 3.1和Python 3.13的简易CMS
  • LLM中 最后一个词语的表征(隐藏状态)通常会融合前面所有词语的信息吗?
  • Java项目集成Log4j2全攻略
  • 速卖通跨境运营破局:亚矩阵云手机如何用“本地化黑科技”撬动俄罗斯市场25%客单价增长
  • 今日行情明日机会——20250709
  • 伪装计算器软件,隐藏手机隐私文件
  • 3.常⽤控件
  • jmeter做跨线程组
  • 第二章:创建登录页面
  • 函数-3-日期函数
  • Java垃圾收集机制Test1
  • css 设置 input 插入光标样式
  • OpenCV图片操作100例:从入门到精通指南(2)
  • java17 gc笔记
  • 论文阅读|汽车虚拟环绕音响系统设计与实现策略的比较研究
  • 新加坡国立大学基于多维度EHR数据实现细粒度患者队列建模,住院时间预测准确率提升16.3%
  • Android网络层架构:统一错误处理的问题分析到解决方案与设计实现
  • java中list.remove(item); // 直接移除会导致ConcurrentModificationException
  • Android ViewModel机制与底层原理详解
  • N8N与Dify:自动化与AI的完美搭配
  • 零基础Qt 5 安装教程
  • 【深度学习新浪潮】什么是蛋白质反向折叠模型?
  • cad_recognition 笔记
  • 前端规范化设计详解
  • ORA-600 kokiasg1故障分析---惜分飞
  • [1-01-01].第50节:泛型 - 泛型的使用
  • Python标准库 bisect 模块
  • 云原生技术与应用-容器技术技术入门与Docker环境部署
  • 【洛谷题单】--顺序结构(一)
  • OSPFv3与OSPFv2不同点