欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页  >  IT编程

C#初中级实战—3DFlipBird(四)缓存池与性能分析(UPR+夜神模拟器)

程序员文章站 2022-03-16 08:11:13
文章目录缓存池概念:制作方法:效果:性能测试:URP添加测试结果分析:标准手机打包(中质量)缓存池无缓存池最高质量打包缓存池无缓存池缓存池概念:缓存池,关键在于缓存二字,如何缓存呢,即保存到某个地方,每次需要创造某个物体时先从缓存池里看看有没有,有就从缓存池里拿出来用,不进行创造。用完了就放到缓存池里面、制作方法:我们每次创建障碍物应该先从缓存池里面找有没有障碍物,有的话就直接从缓存池里面拿出来,又因为我们有很多不同的障碍物,所以我们使用字典,查找对应缓存池是否存在,没有就创建一个,有就放进去。缓...

缓存池概念:

缓存池,关键在于缓存二字,如何缓存呢,即保存到某个地方,每次需要创造某个物体时先从缓存池里看看有没有,有就从缓存池里拿出来用,不进行创造。用完了就放到缓存池里面、

制作方法:

我们每次创建障碍物应该先从缓存池里面找有没有障碍物,有的话就直接从缓存池里面拿出来,又因为我们有很多不同的障碍物,所以我们使用字典,查找对应缓存池是否存在,没有就创建一个,有就放进去。
缓存池字典

public Dictionary<string, PoolDate> poolDic = new Dictionary<string, PoolDate>();

缓存池类:我们找一个父物体,将池子里的东西都放到对应的池子下面


public class PoolDate
{
    public GameObject fatherObj;//缓存对象的父节点
    public List<GameObject> poolList;//对象的容器

    public PoolDate(GameObject obj, GameObject poolObj)
    {
         //给缓存池创造一个父对象,并且将其作为总pool的子物体
        fatherObj = new GameObject(obj.name);
        fatherObj.transform.parent = poolObj.transform;

        poolList = new List<GameObject>() { };
        PushObj(obj);//创建池子时将第一个物体放进去
    }

    /// <summary>
    /// 存物体
    /// </summary>
    /// <param name="obj"></param>
    public void PushObj(GameObject obj)
    {
        obj.SetActive(false);//失活,隐藏
        //存起来
        poolList.Add(obj);
        //设置父对象
        obj.transform.parent = fatherObj.transform;
    }

    /// <summary>
    /// 取物体
    /// </summary>
    /// <param name="name"></param>
    /// <param name="transform"></param>
    /// <returns></returns>
    public GameObject GetObj()
    {
        GameObject obj = null;

        obj = poolList[0];
        poolList.RemoveAt(0);

        obj.SetActive(true);
        //激活显示
        obj.transform.parent = null;//断开父子关系
        return obj;
    }
}

写一个创造方法 替代之前的Instantiate方法

C#初中级实战—3DFlipBird(四)缓存池与性能分析(UPR+夜神模拟器)

我们将物体名字传进去,并且将要创造的物体和位置传进去(如果没有池子,就根据这个创建物体)
传名字是为了给物体改名(一个物体第一次肯定不在池子里,且名字会带clone,目的就是改掉clone,方便存储和取出)

 public GameObject GetObj(string name,GameObject gameObject,Transform transform)
    { 
        //有池子,有东西
        if (poolDic.ContainsKey(name) && poolDic[name].poolList.Count > 0)
        {
            return (poolDic[name].GetObj());
        }
        else
        {
            Debug.Log("物体的名字"+name);
            Debug.Log("物体/池子不存在");
            var reNameObj = GameObject.Instantiate(gameObject, transform);//
            Debug.Log("实例化的物体的名字" + reNameObj.name);
            reNameObj.name = name;
            return null;
        }
        
    }

我们在物体出现一定时间后,不是将物体销毁而是放到对应的池子里。用Push方法替代Destroy方法。
在ObstacleBase脚本里,创建Push方法,传物体自己的名字和自己
C#初中级实战—3DFlipBird(四)缓存池与性能分析(UPR+夜神模拟器)
C#初中级实战—3DFlipBird(四)缓存池与性能分析(UPR+夜神模拟器)
在PoolManager中定义存的方法,判断池子和其中是否有物体,存到对应名字的池子里,并且隐藏物体。(拿出来的时候激活物体)

public void PushObj(string name, GameObject obj)
    {//里面有池子
        if (poolObj == null)
        {
            poolObj = new GameObject("pool");
        }
        obj.SetActive(false);//失活,隐藏
        obj.transform.parent = poolObj.transform;//设置父对象
        if (poolDic.ContainsKey(name))
        {
            poolDic[name].PushObj(obj);
        }else//里面没有,加入一个
        {
            poolDic.Add(name, new PoolDate(obj, poolObj));
        }
    }
    

效果:

C#初中级实战—3DFlipBird(四)缓存池与性能分析(UPR+夜神模拟器)
C#初中级实战—3DFlipBird(四)缓存池与性能分析(UPR+夜神模拟器)
可以看到 Hierarchy窗口出现Pool,里面是不同障碍物对应的池子,每当物体定时时间到了,就会进入缓存池,而另一边创造物体 会优先从缓存池拿物体,当物体不够再进行创造
最后在游戏结束(血量清零)清除缓存池(否则重新开始游戏可能会出现问题),每次开始游戏也可进行缓存池的清除。

C#初中级实战—3DFlipBird(四)缓存池与性能分析(UPR+夜神模拟器)

C#初中级实战—3DFlipBird(四)缓存池与性能分析(UPR+夜神模拟器)

性能测试:

下面进行性能测试,这里用UPR+夜神模拟器进行测评
目前UPR已经不支持直接在编辑器模式下测试了,要么打包测,要么profiler

测评方法:
下载upr windows,下载upr package 加载进项目里面
C#初中级实战—3DFlipBird(四)缓存池与性能分析(UPR+夜神模拟器)
C#初中级实战—3DFlipBird(四)缓存池与性能分析(UPR+夜神模拟器)
项目打包
下载夜神模拟器
C#初中级实战—3DFlipBird(四)缓存池与性能分析(UPR+夜神模拟器)

URP添加测试

开启模拟器同时开启UPR windows,在urp官网登录-我的项目-创建项目-新建测试
C#初中级实战—3DFlipBird(四)缓存池与性能分析(UPR+夜神模拟器)

这里测试4次,两次中质量打包,两次最高质量打包(增加模拟器的渲染压力),其中2次使用缓存池,2次不使用缓存池

将建立好的测试复制Session id到 Windows中,然后选择ADB。此时模拟器应该是打开状态且安装了对应的app,点击之后Start,就开始测试了,测试完点击Stop即可完成测试(官网有视频教程)
C#初中级实战—3DFlipBird(四)缓存池与性能分析(UPR+夜神模拟器)
C#初中级实战—3DFlipBird(四)缓存池与性能分析(UPR+夜神模拟器)

结果分析:

标准手机打包(中质量)

先看标准手机打包(中质量)下,缓存池对于性能的影响C#初中级实战—3DFlipBird(四)缓存池与性能分析(UPR+夜神模拟器)

缓存池

C#初中级实战—3DFlipBird(四)缓存池与性能分析(UPR+夜神模拟器)
C#初中级实战—3DFlipBird(四)缓存池与性能分析(UPR+夜神模拟器)

C#初中级实战—3DFlipBird(四)缓存池与性能分析(UPR+夜神模拟器)

无缓存池

C#初中级实战—3DFlipBird(四)缓存池与性能分析(UPR+夜神模拟器)

C#初中级实战—3DFlipBird(四)缓存池与性能分析(UPR+夜神模拟器)
C#初中级实战—3DFlipBird(四)缓存池与性能分析(UPR+夜神模拟器)
可以看到,缓存池对于性能影响不高,GC的次数居然还多了(可能是测试时间不一样长),GC的峰值时间变长了,帧数基本变化不大,不过使用了缓存池的CPU运行比较平稳,帧数更加稳定。

最高质量打包

下面看如果渲染压力比较高的情况下,缓存池是否会有效果:

C#初中级实战—3DFlipBird(四)缓存池与性能分析(UPR+夜神模拟器)

缓存池

C#初中级实战—3DFlipBird(四)缓存池与性能分析(UPR+夜神模拟器)
内存占用
C#初中级实战—3DFlipBird(四)缓存池与性能分析(UPR+夜神模拟器)
GC
C#初中级实战—3DFlipBird(四)缓存池与性能分析(UPR+夜神模拟器)

无缓存池

C#初中级实战—3DFlipBird(四)缓存池与性能分析(UPR+夜神模拟器)
内存占用
C#初中级实战—3DFlipBird(四)缓存池与性能分析(UPR+夜神模拟器)
GC
C#初中级实战—3DFlipBird(四)缓存池与性能分析(UPR+夜神模拟器)

可以看到,在高渲染压力情况下,帧数直接掉一半,使用了缓存池的帧数还略低一点,内存情况是,使用了缓存池的内存确实用的更多,而且峰值GC时间和 普通画质下的情况一样,都 比不使用缓存池要高。还有一点情况和普通画质一样的是,使用了缓存池的CPU运行时间比不使用缓存池平稳运行时间更长(毛刺更少),说明帧数更稳定。
不过使用了缓存池的GC数量却比不使用更多,这一点比较困惑,也许需要更多测试样本。
对于此项目来说,画质的优化是重头,cpu优化反而不那么重要,两次画质的不同直接导致帧数掉了一半,所以如果要优化,应该往模型面数,贴图尺寸等画面表现来进行(粒子,shader之类的),应该看一下相关参数,不过此次重点是GC对于性能的影响,别的指标就下次再讨论了。(UPR之初体验)

本文地址:https://blog.csdn.net/euphorias/article/details/109241201