游戏开发日志

发布于:2025-07-20 ⋅ 阅读:(15) ⋅ 点赞:(0)

我来为您逐行详细讲解这个 `ViewMgr.cs` 文件。这是一个Unity游戏中的视野管理系统,用于优化游戏性能。

## 文件结构概览

这个文件主要包含以下几个部分:
1. 数据结构和接口定义
2. 视野管理器 `ViewMgr` 类
3. 工具类 `ViewTools`

让我逐行为您讲解:

## 1. 命名空间和引用

```1:7:Scripts/WeiLai/Mgr/ViewMgr.cs
using System.Collections.Generic;
using UnityEngine;
using WeiLai.Common;
using WeiLai.GameWorld.Camera;
using WeiLai.GameWorld;
using UnityEngine.Rendering;
```

这些是必要的引用:
- `System.Collections.Generic` - 用于List和Dictionary
- `UnityEngine` - Unity核心功能
- `WeiLai.Common` - 项目通用功能
- `WeiLai.GameWorld.Camera` - 相机管理
- `WeiLai.GameWorld` - 游戏世界相关
- `UnityEngine.Rendering` - 渲染相关

## 2. 数据结构定义

### GridRangeInt 类

```9:25:Scripts/WeiLai/Mgr/ViewMgr.cs
public class GridRangeInt : IRecycle
{
    public int minPosX;
    public int minPosY;
    public int maxPosX;
    public int maxPosY;

    public void Recycle()
    {
    }

    public void Fetch()
    {
        minPosX = 0;
        minPosY = 0;
        maxPosX = 0;
        maxPosY = 0;
    }
}
```

这个类表示整数网格范围:
- 继承 `IRecycle` 接口,支持对象池回收
- 存储网格的最小和最大X、Y坐标
- `Recycle()` - 回收对象(这里为空实现)
- `Fetch()` - 从对象池获取时重置数据

### GridRangeFloat 类

```27:43:Scripts/WeiLai/Mgr/ViewMgr.cs
public class GridRangeFloat : IRecycle
{
    public float minPosX;
    public float minPosY;
    public float maxPosX;
    public float maxPosY;

    public void Recycle()
    {
    }

    public void Fetch()
    {
        minPosX = 0;
        minPosY = 0;
        maxPosX = 0;
        maxPosY = 0;
    }
}
```

与 `GridRangeInt` 类似,但使用浮点数存储世界坐标范围。

### SkinnerItem 类

```45:70:Scripts/WeiLai/Mgr/ViewMgr.cs
public class SkinnerItem : IRecycle
{
    public IRecycleSkinner m_Skinner;
    public GridRangeInt m_RangeInt;
    public GridRangeFloat m_RangeFloat;

    public void Recycle()
    {
        m_Skinner = null;

        if (m_RangeInt != null)
        {
            m_RangeInt.Recycle();
            m_RangeInt = null;
        }

        if (m_RangeFloat != null)
        {
            m_RangeFloat.Recycle();
            m_RangeFloat = null;
        }
    }

    public void Fetch()
    {
        m_Skinner = null;
        m_RangeFloat = null;
        m_RangeInt = null;
    }
}
```

这个类包装了皮肤对象和其范围信息:
- `m_Skinner` - 实现了 `IRecycleSkinner` 接口的对象
- `m_RangeInt` - 整数网格范围
- `m_RangeFloat` - 浮点数世界坐标范围
- `Recycle()` - 回收时清理所有引用
- `Fetch()` - 获取时重置所有引用

## 3. 接口定义

### IRecycleSkinnerMoveable 接口

```72:85:Scripts/WeiLai/Mgr/ViewMgr.cs
public interface IRecycleSkinnerMoveable
{
    /// <summary>
    /// 进入摄像机视野
    /// </summary>
    public void InCameraView();

    /// <summary>
    /// 退出摄像机视野
    /// </summary>
    public void OutCameraView();
    /// <summary>
    /// 获取位置
    /// </summary>
    public Vector3  GetPosition();
}
```

可移动对象的接口:
- `InCameraView()` - 进入视野时的回调
- `OutCameraView()` - 退出视野时的回调
- `GetPosition()` - 获取当前位置

### IRecycleSkinner 接口

```87:97:Scripts/WeiLai/Mgr/ViewMgr.cs
public interface IRecycleSkinner
{
    /// <summary>
    /// 进入摄像机视野
    /// </summary>
    public void InCameraView();

    /// <summary>
    /// 退出摄像机视野
    /// </summary>
    public void OutCameraView();
}
```

静态对象的接口,比可移动对象少了位置获取方法。

## 4. ViewItem 类

```99:105:Scripts/WeiLai/Mgr/ViewMgr.cs
/// <summary>
/// 存放格子数据的,这个就不缓存了,整个游戏初始化以后一直保留
/// </summary>
public class ViewItem
{
    public bool m_Visible;
    public List<SkinnerItem> m_SkinnerList;
}
```

表示一个网格单元:
- `m_Visible` - 是否在视野内
- `m_SkinnerList` - 该网格内的所有皮肤对象列表

## 5. ViewMgr 主类

### 成员变量

```107:130:Scripts/WeiLai/Mgr/ViewMgr.cs
public class ViewMgr : Singleton<ViewMgr>
{
    /// <summary>
    /// 视野相机
    /// </summary>
    private Camera m_ViewCamera; 
    /// <summary>
    /// 所有的视野对象
    /// </summary>
    private Dictionary<int, ViewItem> m_ItemMap = new Dictionary<int, ViewItem>();
    /// <summary>
    /// 上一次对象
    /// </summary>
    private List<ViewItem> m_LastViewItems = new List<ViewItem>();

    /// <summary>
    /// 怪物listcache
    /// </summary>
    private List<Monster> m_MonsterList = new List<Monster>();
    private List<SceneGridItem> m_SceneGridList = new List<SceneGridItem>();

    /// <summary>
    /// 皮肤和对应皮肤管理对象的缓存容器
    /// </summary>
    private Dictionary<IRecycleSkinner, SkinnerItem>
        m_CacheSkinner = new Dictionary<IRecycleSkinner, SkinnerItem>();

    private List<IRecycleSkinnerMoveable> m_Moveables = new List<IRecycleSkinnerMoveable>();
```

- `m_ViewCamera` - 视野相机引用
- `m_ItemMap` - 所有网格的字典,key是网格ID
- `m_LastViewItems` - 上一帧在视野内的网格列表
- `m_MonsterList` - 视野内怪物的缓存列表
- `m_SceneGridList` - 视野内场景网格的缓存列表
- `m_CacheSkinner` - 皮肤对象到SkinnerItem的映射
- `m_Moveables` - 可移动对象列表

### 初始化方法

```132:135:Scripts/WeiLai/Mgr/ViewMgr.cs
public void InitData()
{
    m_ItemMap.Clear();
}
```

清空所有网格数据。

### 可移动对象管理

```137:147:Scripts/WeiLai/Mgr/ViewMgr.cs
public void AddMoveableItem(IRecycleSkinnerMoveable skinner)
{
    return;

    m_Moveables.Add(skinner);
}

public void RemoveMoveableItem(IRecycleSkinnerMoveable skinner)
{
    return;

    m_Moveables.Remove(skinner);
}
```

注意这里直接返回了,说明可移动对象功能被暂时禁用。

### 添加视野对象

```149:155:Scripts/WeiLai/Mgr/ViewMgr.cs
public void AddViewItem(IRecycleSkinner skinner, float posX, float posY)
{
    return;

    AddViewItem(skinner, ViewTools.GetGridRange(posX, posY), ViewTools.GetGridRangeFloat(posX, posY));
}
```

这个重载方法也被禁用了,原本应该调用下面的完整版本。

```157:200:Scripts/WeiLai/Mgr/ViewMgr.cs
public void AddViewItem(IRecycleSkinner skinner, GridRangeInt gridRange, GridRangeFloat gridRangeFloat)
{
    return;
    if (m_CacheSkinner.ContainsKey(skinner))
    {
        MyLogger.Error("why add again?");
        return;
    }
    
    SkinnerItem skinnerItem = CacheObjectMgr.Inst.Fetch<SkinnerItem>();
    skinnerItem.m_Skinner = skinner;

    skinnerItem.m_RangeInt = gridRange;
    skinnerItem.m_RangeFloat = gridRangeFloat;
    m_CacheSkinner[skinner] = skinnerItem;

    var minX = gridRange.minPosX;
    var minY = gridRange.minPosY;
    var maxX = gridRange.maxPosX;
    var maxY = gridRange.maxPosY;

    //如果对象占用的网格足够大,那就放多个格子上,检测的时候,只要有一个格子在视野内也就显示出来
    for (int i = minX; i <= maxX; i++)
    {
        for (int j = minY; j <= maxY; j++)
        {
            var key = ViewTools.BlockPosToId(i, j);

#if UNITY_EDITOR
            if (key < 0)
            {
                UnityEngine.Debug.LogError("key < 0");
            }
#endif

            if (!m_ItemMap.TryGetValue(key, out var item))
            {
                item = new ViewItem();
                item.m_Visible = true;
                item.m_SkinnerList = new List<SkinnerItem>();
                m_ItemMap.Add(key, item);
            }

            item.m_SkinnerList.Add(skinnerItem);
        }
    }
}
```

这个方法也被禁用了,原本的逻辑是:
1. 检查是否重复添加
2. 从对象池获取SkinnerItem并设置数据
3. 将对象添加到所有覆盖的网格中
4. 如果网格不存在则创建新的

### 移除视野对象

```202:230:Scripts/WeiLai/Mgr/ViewMgr.cs
public void RemoveViewItem(IRecycleSkinner skinner)
{
    return;
    if (!m_CacheSkinner.TryGetValue(skinner, out var skinnerItem))
    {
        return;
    }
    m_CacheSkinner.Remove(skinner);

    if (skinnerItem != null)
    {
        var minX = skinnerItem.m_RangeInt.minPosX;
        var minY = skinnerItem.m_RangeInt.minPosY;
        var maxX = skinnerItem.m_RangeInt.maxPosX;
        var maxY = skinnerItem.m_RangeInt.maxPosY;

        //如果对象占用的网格足够大,那就放多个格子上,检测的时候,只要有一个格子在视野内也就显示出来
        for (int i = minX; i <= maxX; i++)
        {
            for (int j = minY; j <= maxY; j++)
            {
                var key = ViewTools.BlockPosToId(i, j);
                if (m_ItemMap.TryGetValue(key, out var item))
                {
                    skinnerItem.Recycle();
                    item.m_SkinnerList.Remove(skinnerItem);
                }
            }
        }
    }
    else
    {
        MyLogger.Error("skinner not found");
    }
}
```

这个方法也被禁用了,原本的逻辑是:
1. 从缓存中获取SkinnerItem
2. 从所有覆盖的网格中移除该对象
3. 回收SkinnerItem

### 视野检查

```232:242:Scripts/WeiLai/Mgr/ViewMgr.cs
public void CheckSkinnerInView()
{
    if (m_ItemMap.Count > 0)
    {
        //假设所有格子不可见
        foreach (var viewItem in m_LastViewItems)
        {
            viewItem.m_Visible = false;
        }

        _CheckGridItemInView();
    }
}
```

主要的视野检查方法:
1. 先将所有上一帧可见的网格标记为不可见
2. 调用内部方法进行详细检查

### 添加视野内项目

```244:252:Scripts/WeiLai/Mgr/ViewMgr.cs
private void _AddItemInView(ViewItem item)
{
    //设置格子成可见
    item.m_Visible = true;
    if (!m_LastViewItems.Contains(item))
    {
        //保证,只添加一次
        m_LastViewItems.Add(item);
    }
}
```

将网格标记为可见并添加到当前视野列表。

### 检查可移动对象

```254:268:Scripts/WeiLai/Mgr/ViewMgr.cs
private void _CheckMoveableInView(float minX, float minY, float maxX, float maxY)
{
    for (int i = 0; i < m_Moveables.Count; i++)
    {
        var skinner = m_Moveables[i];
        var pos = skinner.GetPosition();
        if (pos.x > minX && pos.x < maxX && pos.y > minY &&
            pos.y < maxY)
        {
            skinner.InCameraView();
        }
        else
        {
            skinner.OutCameraView();
        }
    }
}
```

检查可移动对象是否在视野范围内:
1. 遍历所有可移动对象
2. 获取其位置
3. 判断是否在视野范围内
4. 调用相应的回调方法

### 核心视野检查逻辑

```270:320:Scripts/WeiLai/Mgr/ViewMgr.cs
private void _CheckGridItemInView()
{
    var ctrl = CameraMgr.Inst.m_CameraMoveCtrl;
    
    //扩大1个格子单位,以免出现刚进格子的时候,因加载延迟导致的对象闪烁的效果
    int minX = Mathf.FloorToInt(ctrl.m_MinPosX / CameraMgr.m_ViewWidth) - 1;
    int minY = Mathf.FloorToInt(ctrl.m_MinPosY / CameraMgr.m_ViewHeight) - 1;

    int maxX = Mathf.CeilToInt(ctrl.m_MaxPosX / CameraMgr.m_ViewWidth) + 1;
    int maxY = Mathf.CeilToInt(ctrl.m_MaxPosY / CameraMgr.m_ViewHeight) + 1;

    _CheckMoveableInView(ctrl.m_MinPosX - 2, ctrl.m_MinPosY, ctrl.m_MaxPosX + 2, ctrl.m_MaxPosY);

    //检查在视野内的范围内是否有格子数据,一般没数据就没有格子
    for (int i = minX; i <= maxX; i++)
    {
        for (int j = minY; j <= maxY; j++)
        {
            var key = ViewTools.BlockPosToId(i, j);
            if (m_ItemMap.TryGetValue(key, out var item))
            {
                _AddItemInView(item);
            }
        }
    }

    //更新格子内的对象视野
    var minPosx = ctrl.m_MinPosX - 2;
    var minPosy = ctrl.m_MinPosY - 2;
    var maxPosx = ctrl.m_MaxPosX + 2;
    var maxPosy = ctrl.m_MaxPosY + 2;

    for (int i = m_LastViewItems.Count - 1; i >= 0; i--)
    {
        var item = m_LastViewItems[i];
        if (item.m_Visible)
        {
            for (int j = item.m_SkinnerList.Count - 1; j >= 0; j--)
            {
                //格子部分在视野内,那么就会有的对象在视野范围内,有的对象不在视野范围内
                var skinner = item.m_SkinnerList[j];
                if (ViewTools.CheckCollision(skinner.m_RangeFloat.minPosX,
                        skinner.m_RangeFloat.minPosY,
                        skinner.m_RangeFloat.maxPosX,
                        skinner.m_RangeFloat.maxPosY
                        , minPosx, minPosy, maxPosx, maxPosy))
                {
                    skinner.m_Skinner.InCameraView();
                }
                else
                {
                    skinner.m_Skinner.OutCameraView();
                }
            }
        }
        else
        {
            //整个格子都不在视野内了,那么格子内的对象也都不在视野范围内
            for (int j = item.m_SkinnerList.Count - 1; j >= 0; j--)
            {
                var skinner = item.m_SkinnerList[j];
                skinner.m_Skinner.OutCameraView();
            }

            //不再视野内的移除掉,只保留在视野内的
            m_LastViewItems.RemoveAt(i);
        }
    }
}
```

这是最核心的视野检查逻辑:

1. **计算视野范围**:
   - 获取相机控制器的视野范围
   - 扩大1个格子单位避免闪烁
   - 转换为网格坐标

2. **检查可移动对象**:
   - 调用可移动对象检查方法

3. **检查网格可见性**:
   - 遍历视野范围内的所有网格
   - 如果网格存在数据,标记为可见

4. **更新对象视野状态**:
   - 遍历上一帧可见的网格
   - 对每个网格内的对象进行碰撞检测
   - 根据是否在视野内调用相应的回调
   - 移除不再可见的网格

### 获取视野内对象

```322:340:Scripts/WeiLai/Mgr/ViewMgr.cs
public List<Monster> GetMonstersInView()
{
    if (SceneMgr.Inst.m_CurScene.GetIsCheckView())
    {
        m_MonsterList.Clear();
        for (int i = 0; i < m_LastViewItems.Count; i++)
        {
            var viewItem = m_LastViewItems[i];
            for (int j = 0; j < viewItem.m_SkinnerList.Count; j++)
            {
                var skinnerItem = viewItem.m_SkinnerList[j];
                if (skinnerItem.m_Skinner is Monster monster)
                {
                    m_MonsterList.Add(monster);
                }
            }
        }
    }
    //else
    //{
    //如果不做视野管理,就直接返回m_MonsterList,其怪物在AddViewItem的时候就添加进去且一直存在,直到RemoveViewItem才移除
    //}
    
    return m_MonsterList;
}
```

获取视野内的怪物列表:
1. 检查当前场景是否启用视野检查
2. 清空缓存列表
3. 遍历所有可见网格
4. 提取其中的Monster对象
5. 返回列表

```342:356:Scripts/WeiLai/Mgr/ViewMgr.cs
/// <summary>
/// 获取视野内的格子
/// </summary>
/// <returns></returns>
public List<SceneGridItem> GetGridItemInView()
{
    m_SceneGridList.Clear();
    foreach (var viewItem in m_LastViewItems)
    {
        foreach (var skinnerItem in viewItem.m_SkinnerList)
        {
            if (skinnerItem.m_Skinner is SceneGridItem sceneGridItemData)
            {
                m_SceneGridList.Add(sceneGridItemData);
            }
        }
    }
    return m_SceneGridList;
}
```

获取视野内的场景网格列表,逻辑与获取怪物类似。

### 清理方法

```358:378:Scripts/WeiLai/Mgr/ViewMgr.cs
protected override void OnUnInit()
{
    if(m_CacheSkinner.Count > 0)
    {
        //MyLogger.Error("why has item?");   
    }
    
    foreach (var kvViewItem in m_CacheSkinner)
    {
        kvViewItem.Value.Recycle();
    }
    m_CacheSkinner.Clear();

    m_LastViewItems.Clear();
    m_ItemMap.Clear();
    m_MonsterList.Clear();
        
    base.OnUnInit();
}
```

清理所有数据:
1. 回收所有SkinnerItem
2. 清空所有集合
3. 调用基类清理方法

## 6. ViewTools 工具类

### 静态变量

```382:384:Scripts/WeiLai/Mgr/ViewMgr.cs
public static class ViewTools
{
    public static Vector2 m_GridSize = new(3.8f, 3.0f);
    private static Vector2 m_HalfGridSize = m_GridSize / 2.0f;
```

定义网格大小和半网格大小。

### 网格坐标转换

```386:390:Scripts/WeiLai/Mgr/ViewMgr.cs
public static int BlockPosToId(int x, int y)
{
    return (x + 1000) | ((y + 1000) << 16);
}
```

将网格坐标转换为唯一ID:
- 加1000是为了处理负数坐标
- 使用位运算将X和Y坐标组合成一个整数

```392:396:Scripts/WeiLai/Mgr/ViewMgr.cs
public static void IdToBlockPos(int id, out int x, out int y)
{
    x = id & 0xFFFF - 1000;
    y = (id >> 16) - 1000;
}
```

将ID转换回网格坐标:
- 使用位运算分离X和Y坐标
- 减去1000恢复原始坐标

### 获取网格大小

```398:402:Scripts/WeiLai/Mgr/ViewMgr.cs
public static Vector3 GetGridSize()
{
    //配置的是每个100个像素等于1个unity单位
    return m_GridSize;
}
```

返回网格大小,注释说明100像素=1Unity单位。

### 获取世界坐标范围

```408:418:Scripts/WeiLai/Mgr/ViewMgr.cs
/// <summary>
/// 获取世界坐标的范围
/// </summary>
/// <param name="x"></param>
/// <param name="y"></param>
/// <returns></returns>
public static GridRangeFloat GetGridRangeFloat(float x, float y)
{
    var ret = CacheObjectMgr.Inst.Fetch<GridRangeFloat>();
    ret.minPosX = x - m_HalfGridSize.x;
    ret.minPosY = y - m_HalfGridSize.y;
    ret.maxPosX = x + m_HalfGridSize.x;
    ret.maxPosY = y + m_HalfGridSize.y;
    return ret;
}
```

根据中心点计算世界坐标范围:
1. 从对象池获取GridRangeFloat
2. 计算以中心点为中心的矩形范围
3. 返回范围对象

### 获取网格范围

```424:434:Scripts/WeiLai/Mgr/ViewMgr.cs
/// <summary>
/// 获取占据格子的范围
/// </summary>
/// <param name="x"></param>
/// <param name="y"></param>
/// <returns></returns>
public static GridRangeInt GetGridRange(float x, float y)
{
    var ret = CacheObjectMgr.Inst.Fetch<GridRangeInt>();
    ret.minPosX = Mathf.FloorToInt((x - m_HalfGridSize.x) / CameraMgr.m_ViewWidth);
    ret.maxPosX = Mathf.FloorToInt((x + m_HalfGridSize.x) / CameraMgr.m_ViewWidth);
    ret.minPosY = Mathf.FloorToInt((y - m_HalfGridSize.y) / CameraMgr.m_ViewHeight);
    ret.maxPosY = Mathf.FloorToInt((y + m_HalfGridSize.y) / CameraMgr.m_ViewHeight);
    return ret;
}
```

将世界坐标转换为网格坐标范围:
1. 从对象池获取GridRangeInt
2. 将世界坐标范围除以网格大小
3. 使用FloorToInt确保覆盖所有相关网格

### 碰撞检测

```436:460:Scripts/WeiLai/Mgr/ViewMgr.cs
public static bool CheckCollision(
    float rect1MinX, float rect1MinY, float rect1MaxX, float rect1MaxY,
    float rect2MinX, float rect2MinY, float rect2MaxX, float rect2MaxY)
{
    // 检查x轴是否有重叠
    if (rect1MaxX < rect2MinX)
    {
        return false;
    }

    if (rect2MaxX < rect1MinX)
    {
        return false;
    }

    if (rect1MaxY < rect2MinY)
    {
        return false;
    }

    if (rect2MaxY < rect1MinY)
    {
        return false;
    }

    return true;
}
```

检查两个矩形是否重叠:
1. 检查X轴是否有重叠
2. 检查Y轴是否有重叠
3. 如果任一轴没有重叠,返回false
4. 否则返回true

## 总结

这个视野管理系统的主要特点:

1. **性能优化**:通过网格化视野管理,只渲染视野内的对象
2. **对象池**:使用对象池减少内存分配
3. **双重范围**:同时维护整数网格范围和浮点数世界坐标范围
4. **回调机制**:通过接口回调通知对象进入/退出视野
5. **缓存机制**:缓存视野内的怪物和场景网格列表

目前大部分功能被禁用了(直接return),可能是为了调试或性能测试。

在C#中,protected override void OnInit() 是一个方法的声明,其中的 protected 和 override 是两个关键修饰符,分别表示 访问权限 和 方法重写。以下是详细解释:

1. protected(访问修饰符)

  • 作用:表示该方法只能在 当前类 或 派生类(子类) 中访问,外部类无法直接调用。

  • 对比其他修饰符

    • public:完全公开。

    • private:仅当前类可访问。

    • internal:同一程序集内可访问。
       

      class BaseClass
      {
          protected void ProtectedMethod() { } // 仅基类和子类可调用
      }


      2. override(方法重写)

    • 作用:表示该方法 重写(覆盖)了父类的虚方法(virtual)或抽象方法(abstract

    • 前提条件

      1. 父类中必须存在标记为 virtual 或 abstract 的同名方法。

      2. 方法签名(名称、参数、返回类型)必须完全一致。
         

        class ParentClass
        {
            public virtual void OnInit() { } // 父类虚方法
        }
        
        class ChildClass : ParentClass
        {
            protected override void OnInit() 
            { 
                base.OnInit(); // 可选:调用父类逻辑
                // 子类新增逻辑
            }
        }

        3. 为什么需要 protected override

      3. 封装性protected 确保方法只在继承体系内使用,避免外部误调用。

      4. 多态性override 允许子类自定义父类行为,实现多态(同一方法在不同子类中有不同实现)。

4. 常见应用场景

  • 框架/游戏生命周期方法
    如 Unity 的 OnInit()、ASP.NET Core 的 OnInitialize(),通常由框架基类定义虚方法,子类重写以注入自定义逻辑。

  • 抽象类/接口实现
    若父类是抽象类(abstract),子类必须重写抽象方法。

5. 注意事项

  • new vs override
    若子类方法用 new 修饰,会隐藏父类方法(而非重写),多态调用时仍执行父类逻辑。

  • 密封方法
    若父类方法标记为 sealed override,子类不能再重写。

protected override void OnInit() 的含义:
这是一个受保护的方法,重写了父类的虚方法或抽象方法,允许子类在继承关系中扩展或修改其行为

典型用途:自定义初始化逻辑实现多态响应生命周期事件

List<T> 简介
List<T>
是 .NET 框架中泛型集合类,位于 System.Collections.Generic 命名空间下。
它提供了动态数组的功能,可以存储任意类型的对象,并且在运行时可以根据需要动态调整大小。
PageInfo 类型
PageInfo 是一个自定义类型,通常用于表示 UI 页面的相关信息(例如页面名称、资源路径、是否已加载等)。
该类型可能包含一些属性或方法来管理页面的状态或数据。

UIMgr 


循环遍历 m_Caches 列表
使用一个从后往前(倒序)的 for 循环来遍历 m_Caches 列表。
m_Caches 是一个存储 PageInfo 对象的列表,通常用于缓存已经加载过的 UI 页面信息。
倒序遍历的原因可能是为了在删除元素时不影响前面的索引,避免跳过某些元素。
获取当前迭代的页面对象
var page = m_Caches[i];:从 m_Caches 列表中取出索引为 i 的页面对象,并将其赋值给局部变量 page。
这里的 var 关键字表示隐式类型推断,编译器会根据右侧的表达式自动推断出 page 的类型为 PageInfo。

判断页面类型是否匹配
if (page.m_PageType == ePageType):检查当前页面对象的 m_PageType 属性是否与传入的 ePageType 匹配。
m_PageType 是 PageInfo 类中的一个字段或属性,表示该页面的类型。
ePageType 是一个外部传入的变量,通常是一个枚举值,代表需要查找的目标页面类型。



 


网站公告

今日签到

点亮在社区的每一天
去签到