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

专业网站设计如何提升网页品质怎么做云购网站

专业网站设计如何提升网页品质,怎么做云购网站,建设公司网站费用,可信的h5制作开发大家好#xff0c;这里是七七#xff0c;今天这期是脚本优化的最后一期了。下期的主题是批处理的优势#xff0c;感兴趣的小伙伴们可以收藏本专题#xff0c;七七会持续更新。 话不多说#xff0c;开始今天的内容。 一、最小化反序列化行为 Unity的序列化系统主要用于场…大家好这里是七七今天这期是脚本优化的最后一期了。下期的主题是批处理的优势感兴趣的小伙伴们可以收藏本专题七七会持续更新。 话不多说开始今天的内容。 一、最小化反序列化行为 Unity的序列化系统主要用于场景、预制件、ScriptableObjects和各种资源类型往往派生自ScriptableObject。当其中一种对象类型保存到磁盘时就使用YAML另一种标记语言格式将其转换为文本文件稍后可以将其反序列化为原始对象类型。所有的GameObject及其属性都会在序列化预制件或场景时序列化包括私有的和哦玊保护的字段它们的所有组建及其子GameObjects和组件等。 构建应用程序时这些序列化的数据会捆绑在大型二进制数据文件中这些文件在Unity内部被称为序列化文件。在运行时从磁盘读取和反序列化数据是一个非常慢的过程相对而言因此所有的反序列化活动都伴随着显著的性能成本。 这种反序列化在 调用Resources.load时发生用于在名为Resources的文件夹中查找文件路径。一旦数据从磁盘加载到内存中以后重新加载相同的引用会快得多但在第一次访问时总是需要磁盘活动。当然需要反序列化的数据集越大此过程所需的时间就越长。由于预制组件的每个组件都是序列化的因此层次结构越深需要反序列化的数据就越多。这对于具有很深层次结构的预制块带有许多空GameObject对象的预制块来说是一个问题对于用户界面UI预制块来说尤其是个问题因为他们往往比典型的预制块容纳更多的组件。 像这样加载大型序列化数据集可能在第一次加载时造成CPU的显著峰值如果在场景开始时立即需要它们则会增加加载时间。更重要的是如果在运行时加载它们可能会导致掉帧。可以用几种方法来最小化反序列化的成本。 1.1减小序列化对象 我们的目标应该是使序列化的对象尽可能小或者将它们分割成更小的数据块然后一块一块地组合在一起这样它们就可以一次加载一块。这对于预制版来说是很棘手的因为Unity本身并不支持嵌套的预制版所以我们将自己实现这样一个系统这在Unity中是一个非常难解决的问题。UI预制块很适合分割成更小的块因为通常在任何时候都不需要整个UI所以通常可以一次加载一个。 1.2异步加载序列化对象 可以通过Resources.LoadAsync以异步方式加载预制块和其他序列化的内容这将把从磁盘读取的任务转移到工作的线程上从而减轻主线程的负担。将序列化的对象变为可用需要一些时间可以通过检查前面的方法调用返回的ResourceRequest对象的isDone属性判断是否完成序列化对象加载。 这对于游戏开始时立即需要的预制组件来说并不理想但如果愿意创建管理这种行为的系统那么所有未来的预制组件都是异步加载的良好候选对象 1.3在内存中保存之前加载过的序列化对象 如前所述一旦序列化对象加载到内存中它就会保留在内存中如果以后需要可以复制它例如实例化更多的预制副本。通过显式地调用Resource.Unload可以释放这些数据这将释放内存空间供以后重用。但是如果在应用程序的预算中有很多剩余的内存就可以选择将这些数据保存在内存中这将减少以后从磁盘重新加载数据的需要。这自然会消耗大量内存来保存越来越多的序列化数据使其成为内存管理的一种风险策略因此应该只在必要时才这样做。 1.4将公共数据移入ScriptableObject 如果有许多不同的预制件其中的组件包含许多倾向于共享数据的属性例如游戏设计值如命中率、攻击力、双爆等那么所有这些数据都将序列化到使用它们的每个预制件中。更好的方法是将这些公共数据序列化到ScriptableObject中然后加载并使用它。这减少了存储在预制文件中的序列化数据量并可以避免过多的重复工作显著减少场景的加载时间。 二、叠加、异步地加载场景 可以加载场景来替换当前场景也可以添加内容到当前场景中而不写在前一个场景。这可以通过SceneManager.LoadScene函数家族的LoadSceneMode参数进行切换。 另一种场景加载模式是同步或异步完成两者各有千秋。同步加载是通过调用SceneManager.LoadScene加载场景的典型方法其中主线程将阻塞直到给定的场景完成加载。者通常会导致糟糕的用户体验因为游戏在加载内容时似乎会卡住无论是替换还是附加方式。如果想让玩家尽快进行后续操作或没有时间等待场景对象出现最好使用同步加载模式。如果在游戏的第一关加载或者返回到主菜单通常会使用这种模式。 然而对于未来的场景加载可能希望减少性能影响让玩家继续操作下去。加载场景需要很多工作场景越大加载时间越长。然而异步叠加式加载选项提供了巨大优势可以让场景逐渐加载到背景中而不会对用户体验造成明显的影响。为此可以使用SceneManager.LoadSceneAsync并传递LoadSceneMode.Additive以加载模式函数。 重要的是要意识到场景并不严格遵循游戏关卡的概念。在大多数游戏中玩家通常被限制在一个关卡中但Unity可以通过叠加式加载支持多个场景同时加载允许每个场景代表一个关卡的一小块。因此可以为关卡初始化第一个场景并在玩家接近下一章节时异步叠加式加载下一章节并在玩家穿越关卡时不断重复这一过程。 利用这一功能需要一个系统不断检查玩家在关卡中的位置知道玩家接近或者用Trigger Volumes广播玩家将进入下一章节的消息并在适当的时候开始异步加载。另一个重要的考虑是场景的内容不会立即出现因为异步加载可以有效地将加载分散到几个帧上从而使可见影响尽可能减小。需要却吧出发场景的异步加载有足够的时间以便玩家不会看到对象弹出到游戏中。 场景可以卸载从内存中清除出来。这将删除任何不再需要的Update的组件节省一些内存或提升一些运行时性能。同时这可以通过SceneManager.UnloadScene和SceneManager.UnloadSceneAsync同步或异步地完成。这是一个巨大的性能优势因为根据玩家在关卡中的位置只使用需要的内容但请注意不可能卸载单一场景的小块。如果原始场景文件很大那么卸载它将卸载所有内容。原来的场景必须分解成更小的场景然后根据需要加载和卸载。同样应该只在玩家不再能看到场景的组件对象时才开始卸载场景否则玩家将看到物体凭空消失。最后要考虑的是场景卸载会导致许多对象被销毁这可能是放大量内存并触发垃圾回收。在使用这个技巧时有效地使用内存也很重要。 这种方法需要大量的场景重新设计、脚本编写、测试和调试工作这是不可低估的但是改进用户体验的好处是非常多的。在游戏中拥有区域间的无缝过渡是一种经常受到玩家称赞的优点因为它不会打断玩家的操作。如果适当地使用它就可以显著提升运行时的性能进一步改善用户体验。 三、创建自定义的Update层 在前面我们讨论了使用这些Unity Engine特性来避免在大多数帧中出现过多CPU工作负载的优缺点。不管采用哪种方法都存在一个额外的风险即需要编写大量的MonoBehaviour来定期调用某个函数这意味着在同一帧中同时触发了太多的方法。 想象一下成千上万的MonoBehaviour在场景开始时一起初始化每个MonoBehaviour同时启动一个协程每500毫秒处理一次AI任务。它们极有可能在同一帧内触发导致CPU使用率在一段时间内出现一个巨大的峰值接着会临时下降然后在处理下一轮AI时再次出现峰值。理想情况下我们希望随时间分散这些 调用下面是这个问题的可能解决方案 每次计时器过期或协程触发时生成一个随机等待时间将协程的初始化分散到每个帧中这样每个帧中只会启动少量的协程初始化将调用更新的指责传递给某个God类该类对每个帧的调用数量进行了限制 前两个选项很有吸引力因为它们相对简单而且协程可以潜在地减少大量不必要的开销。然而如前所述这种剧烈的设计更改会带来许多危险和意想不到的副作用。 优化更新的一个更好的方法是根本不使用Update或者更准确地说只使用一次。当Unity调用Update时实际上是调用它的任何回调都要经过前文提到的本机-托管的桥接这可能是一个代价高昂的任务。换句话说执行1000个单独的Update回调的处理成本比执行一个Update回调要高后者调用1000个常规函数。调用Update数千次的工作量不是CPU很容易承担的这主要是因为桥接。因此让一个God类的MonoBehaviour使用它自己的Update回调来调用自定义组件使用的自定义更新样式的系统可以最小化Unity需要跨越桥接的频率。 事实上许多Unity开发人员更喜欢从项目一开始就实现这个设计因为它可以让他们更好地控制更新何时以如何在整个系统中传播这可以用于菜单暂停、冷却时间操作效果或对重要任务进行优先级排序以及如果发现即将达到当前帧的CPU预算就暂停低优先级任务。 所有想要与这样一个系统集成的对象必须有一个公共的入口点为此可以使用interface关键字的接口类。接口类本质上建立了一个契约任何实现接口类的类都必须提供一系列特定的方法。换句话说如果知道对象实现了一个接口类就可以确定哪些方法是可用的。在C#中类只能从单个基类派生但可以实现任意数量的接口类。 下面的接口类定义就足够了它只需要实现类定义一个名为OnUpdate的方法 public interface IUpdateable{void OnUpdate(float dt);} 提示通常的做法是用大写的I来开始接口类定义以清楚地表明我们正在处理的事接口类。接口类的优点在于它们改善了代码库的解藕能力允许替换大型子系统只要坚持使用接口类它就能继续按预期工作。 接下来定义一个实现该接口类的MonoBehaviour类型 public class UpdateableComponent : MonoBehaviour, IUpdateable{public virtual void OnUpdate(float dt) { }} 注意将方法命名为OnUpdate而不是Update。我们定义了相同概念的自定义版本但要避免和内建Update回调的命名冲突。 UpdateableComponent类的OnUpdate方法检索当前的时间增量dt节省了大量不必要的Time.deltaTime调用。该调用通常用于Update回调。还将该函数设为虚函数以允许派生类对其进行自定义。 这个函数将永远不会被调用因为目前正在写此函数。Unity会自动获取并调用用Update名称定义的方法但没有OnUpdate函数的概念所以需要实现一些功能在适当的时候调用这个方法。例如某种GameLogicGod类可以用于此目的。 在这个组件的初始化期间应该执行一些操作来通知GameLogic对象它的存在和销毁这样它就知道什么时候开始和停止调用其OnUpdate函数。 在下面的示例中假设GameLogic类是一个SingletonComponent且具有为注册和注销而定义的适当的静态函数。记住可以很容易地使用消息传递系统来通知GameLogic它的创建/销毁。 为了MonoBehaviour挂载进此系统最合适的地方是在它们的Start和OnDestroy回调中处理 void Start(){GameLogic.Instance.RegisterUpdateableObject(this);}void OnDestroy(){if (GameLogic.Instance.IsAlive){GmeLogic.Instance.DeregisterUpdateableObject(this);}} 最好使用Start方法来完成注册任务因为使用Start意味着可以确定所有其他已经存在的组件至少在此以前已经调用了Awake方法。这样在开始调用对象的更新之前任何关键的初始化工作都已经在对象上完成了。 注意因为在MonoBehaviour基类中使用Start如果在派生类中定义Start方法它将有效地覆盖基类定义而Unity将获取派生的Start方法作为回调。因此明智的做法是实现一个Initialize虚方法这样派生类就可以覆盖它来定制初始化行为而不会影响基类通知GameLogic对象组件存在的任务。 下面代码演示了如何实现Initialize虚方法 void Start(){GameLogic.Instance.RegisterUpdateableObject(this);Initialize();}protected virtual void Initialize(){} 最后需要实现GameLogic类。不管它是SingletonComponent还是MonoBehaviour不管它是否使用消息传递系统实现代码实际上都是相同的。不管怎样UpdateableComponent类必须注册并注销为IUpdateable对象而GameLogic类必须使用它自己的Update回调来遍历每个组册的对象并调用其OnUpdate函数。 这时GameLogic类的定义 public class GameLogicSingletonComponent:SingletonComponentGameLogicSingletonComponent {public static GameLogicSingletonComponent Instance{get { return ((GameLogicSingletonComponent)_Instance); }set { _Instance value; }}ListIUpdateable _updateableObjects new ListIUpdateable();public void RegisterUpdateableObject(IUpdateable obj){if (!_updateableObjects.Contains(obj){_updateableObjects.Add(obj);}}public void DeregisterUpdateableObject(IUpdateable obj){if (_updateableObjects.Contains(obj){_updateableObjects.Remove(obj);}}void Update(){float dt Time.deltaTime;for(int i0;i _updateableObjects.Count; i){_updateableObjects[i].OnUpdate(dt);}} } 如果确保所有自定义组件都继承自UpdateableComponent类那么实际上用一个Update回调和N个虚函数调用替换了Update回调的N次调用。这可以节省大量的性能卡小因为虽然调用虚函数开销比非虚函数调用掠夺因为它需哟调用重定向到正确的地方仍然将更新行为的绝大多数放在托管代码中尽可能避免Native-Managed桥。这个类甚至可以扩展为提供优先级系统如果它检测到当前帧花费的时间太长就可以跳过低优先级任务还有许多其他的可能性。 根据对当前项目的深入程度这样的更改可能令人生畏、耗时并且可能会在更新子系统以利用一组完全不同的依赖项时引入大量bug。然而如果时间充裕耗时就会大于风险。明智的做法是对场景中的一组对象进行测试这些对象与当前场景文件的设计类似以验证收益大于成本。
http://www.pierceye.com/news/770484/

相关文章:

  • 番禺网站建设策划江阴市建设局官网站
  • 建设网站模块需要哪些内容石家庄城乡建设厅网站
  • 公司网站后台管理网络公司名字大全三字
  • 广西住房建设厅网站广州seo工作
  • 做分销商城网站的wordpress 知更鸟 网格
  • 推销商务网站的途径有哪些爱网站查询挖掘工具
  • 苏州现代建设公司网站备案的域名做电影网站
  • 长沙seo网站优化公司wordpress5.1下载
  • 七星彩网投网站建设鹤壁公司做网站
  • 多语言企业网站建设费用怎么自己做购物网站
  • 中国网站排名前100线上网站开发相关书籍
  • 网站制作图书网站建设指南
  • 网站备案简单吗优化关键词排名软件
  • 泉山网站开发安徽建设工程造价信息网
  • 如何使用电子商务网站做seo需要用到什么软件
  • 新乡商城网站建设哪家专业潮汕学院网站开发
  • 西安响应式网站开发网站空间多少钱一年
  • 做电子相册的大网站怎样提高网站的权重
  • seo网站设计外包去哪个网站有客户找做标书的
  • 微商招商网站源码互联网营销推广方案
  • 深圳做网站服务公司河北石家庄最新新闻
  • 山东济南seo整站优化唐山网站建设那家性价比高
  • c 可以做哪些网站小说网站建设采集
  • 公司网站备案条件高校网站集群平台子站开发
  • 制作网站能赚钱吗单位发购物或电影卡有哪些app
  • 我们网站在那里登陆后台系统管理网站建设服务咨询
  • 免费上传图片的网址网站seo工作内容
  • chatgpt 网站一对一直播软件开发
  • 网站做排行多少费用个人电脑做网站打不开数据库
  • 做网站是比特币的滁州做网站电话号码