当前位置: 首页 > 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.lryc.cn/news/583239.html

相关文章:

  • 码云创建分支
  • 分库分表之实战-sharding-JDBC绑定表配置实战
  • 掌握PDF转CAD技巧,提升工程设计效率
  • 模型内部进行特征提取时,除了“减法”之外,还有哪些技术
  • Android ttyS2无法打开该如何配置 + ttyS0和ttyS1可以
  • BEV感知算法:自动驾驶的“上帝视角“革命
  • c语言学习_函数递归2
  • 深度学习模型在C++平台的部署
  • Spring Boot微服务中集成gRPC实践经验分享
  • 1️⃣理解大语言模型
  • 百度文心一言开源ERNIE-4.5深度测评报告:技术架构解读与性能对比
  • Shell 脚本0基础教学(一)
  • 【计算机组成原理——知识点总结】-(总线与输入输出设备)-学习笔记总结-复习用
  • Energy-Based Transformers:实现通用系统2思维的新范式
  • HOOPS Communicator 2025.5.0版本更新速览:性能、测量与UI全面优化
  • C++入门基础篇(一)
  • 《【第五篇】图片处理自动化:让你的视觉内容更专业!:图片处理基础与批量裁剪》
  • Unity Demo-3DFarm详解-其二
  • 极简相册管理ios app Tech Support
  • 无人机报警器频段模块设计与运行要点
  • Excel 常用高级用法
  • 使用LLaMA-Factory微调Qwen2.5-VL-3B 的目标检测任务-使用LLaMA-Factory webui进行训练
  • 学习日志08 python
  • 基于svga+uniapp的微信小程序动画组件开发指南
  • 前端进阶之路-从传统前端到VUE-JS(第四期-VUE-JS页面布局与动态内容实现)(Element Plus方式)
  • IntelliJ IDEA 2025.1.3创建不了java8的项目
  • 【PTA数据结构 | C语言版】大整数相加运算
  • Linux驱动05 --- TCP 服务器
  • PostgreSQL如何进行跨服务器迁移数据
  • 70、【OS】【Nuttx】【构建】配置 stm32 工程