游戏开发学习记录

初始化只是第一次实例化的时候调用,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.pswp.cn/web/88136.shtml
繁体地址,请注明出处:http://hk.pswp.cn/web/88136.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

一级缓存与二级缓存深度剖析:作用域、配置与同步方案全解析

引言 在分布式系统与高并发场景下&#xff0c;缓存机制已成为提升系统性能的关键技术。本文从作用域、失效机制、配置实践到同步方案&#xff0c;系统化解析一级缓存与二级缓存的核心差异与工程实践。 一、一级缓存&#xff1a;会话级数据加速器 1.1 作用域与生命周期 作用域&a…

OneCode MQTT插件开发实战:基于Paho.Client的物联网通信解决方案

引言 在物联网应用开发中&#xff0c;MQTT协议因其轻量、低带宽占用的特性被广泛采用。OneCode平台提供的xui.MQTT插件基于Eclipse Paho.Client实现了完整的MQTT通信能力&#xff0c;本文将从插件用途、核心实现、开发要点和功能扩展四个维度&#xff0c;详解如何基于该插件构建…

1.1_5_1 计算机网络的性能指标(上)

在这个小节中我们要学习计算机网络的性能指标&#xff0c;我们在考研当中主要掌握这样的七个性能指标&#xff0c;分别是速率、带宽、吞吐量、时延、时延带宽积、往返时延和信道利用率。我会把相关性比较紧密的性能指标放在一起讲解。在这个视频中&#xff0c;我们先来学习前三…

Python 性能优化指南:深入剖析代码分析与优化工具

Python 性能优化指南:深入剖析代码分析与优化工具 在 Python 的广泛应用场景中,性能优化既是挑战,也是机遇。无论是构建 Web 应用还是处理数据分析,理解代码性能瓶颈并有效优化至关重要。本文将探讨 Python 代码性能分析的核心方法,并逐步解析关键工具的使用技巧,带您从…

力扣打卡第二十一天 中后遍历+中前遍历 构造二叉树

106. 从中序与后序遍历序列构造二叉树 给定两个整数数组 inorder 和 postorder &#xff0c;其中 inorder 是二叉树的中序遍历&#xff0c; postorder 是同一棵树的后序遍历&#xff0c;请你构造并返回这颗 二叉树 。 示例 1: 输入&#xff1a;inorder [9,3,15,20,7], postor…

Notepad++正则表达全解

摘要:Notepad正则表达式符号大全包含11类常用语法&#xff1a;基础符号&#xff08;.^$?等&#xff09;、预定义字符类&#xff08;\d\w\s等&#xff09;、锚点&#xff08;\b\B&#xff09;、量词&#xff08;{n,m}&#xff09;、分组引用&#xff08;()$1&#xff09;、字符…

前后端分离(java) 和 Nginx在服务器上的完整部署方案(redis、minio)

一、准备工作 服务器环境要求 银河麒麟 V10 操作系统 开放端口&#xff1a;MinIO (9000、9001)、 Redis (6379)、应用服务 jar包(18888)、前端服务(8080) 系统用户&#xff1a;具有 sudo 权限的用户 操作&#xff1a;需要先有必备的工具前端的vsCode,webStrom、后台的idea&…

贪心算法:简单而高效的求解策略C++

贪心算法详解及C实现 1. 什么是贪心算法 贪心算法&#xff08;Greedy Algorithm&#xff09;是一种在每一步选择中都采取在当前状态下最好或最优&#xff08;即最有利&#xff09;的选择&#xff0c;从而希望导致结果是全局最好或最优的算法策略。 贪心算法与动态规划不同在于它…

IDEA 中使用 <jsp:useBean>动作指令时,class属性引用无效

问题&#xff1a;在 IDEA 中创建 Java Web项目&#xff0c;在src/model包下存在一个Student类该类中包含&#xff1a;全参构造器、私有属性的get/set方法。然后在 jsp 页面中使用 <jsp:useBean>创建Student类的对象&#xff1a;访问页面时报错&#xff1a;原因&#xff1…

【网络】Linux 内核优化实战 - net.core.flow_limit_table_len

目录参数作用查看与修改调优建议相关警告net.core.flow_limit_table_len 是 Linux 内核中的一个网络参数&#xff0c;用于控制**流限制表&#xff08;Flow Limit Table&#xff09;**的大小。这个表主要用于限制网络流量中单个"流"&#xff08;通常指来自同一源IP、端…

前端开发常见问题技术文章大纲

前端开发常见问题技术文章大纲 常见性能优化问题 页面加载速度慢的原因及解决方案渲染阻塞资源的优化方法内存泄漏的检测与修复 跨浏览器兼容性问题 不同浏览器对CSS和JavaScript的支持差异Polyfill和Shim的使用场景如何利用工具检测兼容性问题 响应式设计挑战 媒体查询的最佳实…

Redis常见性能问题和解决方案有哪些?

Redis 作为高性能的内存数据库&#xff0c;在实际使用中可能会遇到性能问题。以下是常见的性能问题及其解决方案&#xff0c;用中文总结如下&#xff1a; 1. 高延迟问题 问题描述&#xff1a;客户端请求响应时间过长&#xff0c;可能由于网络、命令复杂度或服务器负载导致。 解…

闪测仪应用案例丨手机中框如何突破「尺寸检测」瓶颈?

越来越多的手机中框&#xff0c;正改为更复杂的镂空设计&#xff0c;这种设计不仅保持了手机中框的结构强度&#xff0c;还进一步减轻了机身重量&#xff0c;同时提升了散热性能。这让手机中框的自动化生产增加了很多难点&#xff0c;其中的尺寸检测就遇到了许多瓶颈。▪ 尺寸精…

【字节跳动】数据挖掘面试题0011:介绍下时间序列分析常用知识点

文章大纲时间序列分析全面解析一、时间序列分析的基本概念二、时间序列分析的主要方法1. 描述性分析2.统计分析方法3.预测模型&#xff08;1&#xff09;传统统计模型&#xff08;2&#xff09;现代机器学习模型三、时间序列分析的应用场景四、模型评估五、在字节跳动的应用场景…

ubuntu中交叉编译iperf3到目标平台xilinx

注&#xff1a;此文为ubuntu x86系统编译程序到xilinx aarch64系统中。 一、工具准备 x86上编译aarch64的编译器 sudo apt install gcc-aarch64-linux-gnu g-aarch64-linux-gnu #保证编译器在环境变量中&#xff0c;尝试执行aarch64-linux-gnu-gcc 目标平台的根文件系统rootf…

Java-数据结构-集合框架

什么是集合框架集合本质是java所实现的一组数据结构&#xff0c;提供了不同的增删改查方法。集合就是定义了接口&#xff0c;再通过不同的类去实现定义的接口&#xff0c;这些实现了接口的类就是集合类&#xff0c;例如list&#xff0c;stack&#xff0c;map。集合框架的重要性…

黑马点评系列问题之基础篇16jedis redis依赖引入后仍然还是报错

问题描述依赖已经导入进去了&#xff0c;在仓库里有***.jar和***.pom这两个文件&#xff0c;但是点开右面的maven还是有很多爆红。点击maven里的更新还是不行。解决点到配置文件pom.xml在lombok这个依赖的代码下面&#xff0c;添加上版本号&#xff0c;刷新一下右键单击pom.xml…

SQL 一键转 GORM 模型,支持字段注释、类型映射、tag 自定义!

SQL 一键转 GORM 模型&#xff0c;支持字段注释、类型映射、tag 自定义&#xff01; 在使用 Golang GORM 开发项目时&#xff0c;你是否也经历过这些「重复性痛苦」&#xff1a; ✅ 拿到建表 SQL&#xff0c;要手动写 struct✅ 字段多、类型复杂&#xff0c;还要写 json、go…

前端计算机视觉:使用 OpenCV.js 在浏览器中实现图像处理

一、OpenCV.js 简介与环境搭建OpenCV&#xff08;Open Source Computer Vision Library&#xff09;是一个强大的计算机视觉库&#xff0c;广泛应用于图像和视频处理领域。传统上&#xff0c;OpenCV 主要在后端使用 Python 或 C 等语言。但随着 WebAssembly (Wasm) 技术的发展&…

开发在线商店:基于Vue2+ElementUI的电商平台前端实践

Hi&#xff0c;我是布兰妮甜 &#xff01;在当今数字化时代&#xff0c;电子商务已成为商业领域的重要组成部分。开发一个功能完善、用户友好的在线商店应用对于企业拓展市场至关重要。本文将详细介绍如何使用Vue2框架配合ElementUI组件库开发一个完整的在线商店应用。 文章目录…