在使用Unity3d开发游戏的时,我们总会涉及Unity内置的生命周期函数。弄清这些函数的调用顺序和特性十分重要,因为这影响到逻辑的执行顺序,例如:初始化要在使用之前,注册回调要在响应之前等等。

通常说来,在大型商业项目中,我们需要自制一套游戏循环,来满足多变的游戏玩法。哪些现有的生命周期函数可以使用?哪些需要被替换掉?这些取舍贯穿了整个游戏开发过程。

生命周期

Unity3d的函数调用有固定的顺序,对于脚本生命周期(Script Lifecycle),官方文档中给出一张时序图如下:

深入理解这张图,可以应对大多数的时序问题。在Initialization、Disable/enable、Decommissioning区域的函数只会调用有限次数,而其他部分都是受控重复或循环调用。其中:

  • Awake 函数在构造脚本对象时调用
  • OnEnable/OnDisable 在每次激活对象时调用
  • Start 在第一次触发脚本时调用
  • OnDestory 在销毁对象时调用

主循环分为物理模拟、游戏逻辑、渲染绘制三个子循环。从Unity实现的方式上看,这三个循环放是在同一个线程中。不过自从Unity3d的5.x版本后,引擎加入了多线程渲染的选项,即将第三步循环放在另一个线程中进行。这样做就可以在固定帧率下降低逻辑循环的压力,降低掉帧现象的发生。至于物理模拟循环,我个人觉得没必要拆出到另一个线程。毕竟线程间通信也需要性能,而物理模拟循环运行到速度一般要快于游戏逻辑,如果出现数据访问的冲突还需要加锁,就得不偿失了。本文内容出自《游戏架构:核心技术与面试精粹》,感兴趣的读者可以在主流电商网站上查到。

重写模版脚本

在实际项目中,我会通过更改代码的模板文件,来优化生命周期函数的使用方式。在Unity的安装目录中,有创建代码的模版文件。通过自定义这个文件,可以更改创建默认文件的内容。文件目录为:

  • Windows: Unity安装目录/Editor/Data/Resources/ScriptTemplates/81-C# Script-NewBehaviourScript.cs.txt
  • Mac: Unity安装目录/Contents/Resources/ScriptTemplates/81-C# Script-NewBehaviourScript.cs.txt

根据自己团队开发人员的编程习惯,我自定义了一个代码模版。大家可以根据自己的需要做相应的更改。

using UnityEngine;
using System.Collections;public class #SCRIPTNAME# : MonoBehaviour
{#region Public Attributes#endregion#region Private Attributes#endregion#region Unity Messages
//    void Awake()
//    {//
//    }
//    void OnEnable()
//    {//
//    }
//
//    void Start()
//    {//
//    }
//
//    void Update()
//    {//
//    }
//
//    void OnDisable()
//    {//
//    }
//
//    void OnDestroy()
//    {//
//    }#endregion#region Public Methods#endregion#region Override Methods#endregion#region Private Methods#endregion#region Inner#endregion
}

代码模版中添加了常用的生命周期函数,并按照顺序进行排列。由于空函数也会产生性能消耗,这里采用注释的方式规避这个弊端。另外,我按用途添加了几个#region分隔函数区域。#region是C#的功能,可以标定折叠区域,方便查找对应函数。

游戏循环

了解Unity自带的生命周期函数之后,再看看游戏循环应该如何设计。游戏归根结底是由交互序列组成的。因此它必然会有一个基础的结构:

while (true)
{Input();Update();Render();
}

从这个层面看,游戏循环由三部分组成,分别是

  1. 非阻塞的用户输入
  2. 更新游戏逻辑状态
  3. 渲染游戏画面

每次循环完成后,会更新一次画面的绘制,这个过程也被称为帧(Frame)。使用帧率(FPS,Frame Per Second)可以标定游戏循环的速率与真实时间的映射关系。帧率值越小,意味着游戏越“卡”。游戏在电脑或家用主机上,通常为60帧/秒,手机上为30帧/秒。另一方面,帧率的倒数即为每帧所占用的时长,单位通常为毫秒。影响帧率的主要因素是每帧需要做的工作。例如复杂的物理计算,游戏逻辑的处理,图形细节控制等。这些都会占据CPU与GPU。如果处理操作的时长超过帧率的倒数,那么就会拖慢帧率。这种现象被成为“掉帧”。

固定帧率模式

一般说来,我们有个期望的帧率,如果每帧的运行时长短,那么帧率就会超过预定的标准,因此我们通常会在循环的末尾加入延期等待。假定我有个Sleep函数可以阻塞线程执行,那么这个模式的代码结构如下:

while (true)
{double start = getCurrentTime();Input();Update();Render();sleep(start + 1/FPS - getCurrentTime());
}

在这种结构中,帧率不会超过预定数值。在Unity3d中可以通过下面的代码设置:

Application.targetFrameRate = FPS;

追赶模式

这种模式可以更好的处理掉帧引发的逻辑问题。大体思路是,当出现掉帧时,只运行逻辑,不绘制画面,用节省下来的时间追赶落后的帧。这种策略会降低图形绘制的频率,但可以保证逻辑的执行。

具体说来,每次Render执行之前,要保证累计运行时长到达阈值。如果出现卡顿,后面的帧会多次执行Update,直到赶上之前的帧为止。代码结构如下:

double preFrameTime = getCurrentTime();
double lag = 0.0;
while (true)
{double current = getCurrentTime();double elapsed = current - preFrameTime;preFrameTime = current;lag += elapsed;Input();while (lag >= 1/FPS){Update();lag -= 1/FPS;}Render();
}

使用这种模式时,要注意不要将FPS设置的太大,否则最慢的机器将永远赶不上时间,它将卡在死循环中。对于较差的机器,Render在这逻辑循环之外,所以总体上看还是会节省一些时间。虽然看起来会比较卡,但还是能够正确的运行游戏。

在Unity3d中,对应这个模式的循环是FixUpdate。Unity中设置Fixed Timestep可以控制FixedUpdate速率,其数值为时长周期。如果FixedUpdate在限定的时间执行不完,图形绘制频率会降低,以保证物理的执行。另一方面,设置Maximum Allowed Timestep可以防止逻辑执行时间过长,卡死线程。

总结

Unity3d作为完整的引擎,常见的生命周期函数与游戏循环模式都已具备。但作为特定的游戏,通常有自己的特点。例如,竞速类游戏与MMO网游在游戏循环的设计上就有很大的差别。竞速类型对实时反馈的要求很高,如果采用追赶模式,抽帧造成的体验就会很差。在掉帧方面,MMO网游面临的则是,角色在场景中漫游时,其他玩家的模型加载与位置同步造成的卡顿。这种情况下,可能会使用分帧加载、AOI ( Area Of Interest ) 等处理方法保障游戏的流畅。

因此,游戏循环通常是每个项目根据自己的特点“独家定制”。在深入理解Unity3d的生命周期函数后,我们就可以在其基础上,自主独立的搭建个性化的游戏循环框架。

本文出自我的编写的书:

主流电商网站有售:

  • 京东
  • 淘宝
  • 当当
  • china-pub

Unity3d 制定游戏循环的策略相关推荐

  1. android unity hook,[原创]Unity3d安卓游戏DLL动态调式与HOOK基础

    [原创]Unity3d安卓游戏DLL动态调式与HOOK基础 2016-4-4 02:40 8207 [原创]Unity3d安卓游戏DLL动态调式与HOOK基础 2016-4-4 02:40 8207 ...

  2. 【CSDN英雄会】囯炬CEO张代浩:做写架构的人,做制定游戏规则的人

    英雄会是CSDN旗下针对国内IT技术领域专家展示和交流的平台.通过线下线上的互动形式,为CSDN社区专家提供更多学习.合作.宣传的机会.英雄会后续将在北上广深等国内一二线城市建立分会,各个分会后期将组 ...

  3. 大话游戏循环Game Loop——PythonC++

    目录 前言 什么是游戏循环? 游戏循环的意义 从结构上来看: 从功能上来看: 正文 一个简单的游戏循环 阻塞游戏循环 现代基础游戏循环 "时间" 固定帧率游戏循环 时间驱动不固定帧 ...

  4. 游戏开发 unity3d python_游戏研发系列 Unity3D/2D游戏开发从0到1 第2版.pdf

    作 者 :刘国柱著 出版发行 : 北京:电子工业出版社 , 2018.01 ISBN号 :978-7-121-33499-3 页 数 : 507 丛书名 : 游戏研发系列 原书定价 : 99.00 开 ...

  5. android 开发游戏_Android游戏开发–基本游戏循环

    android 开发游戏 在到目前为止的系列之后,您将对游戏架构有所了解. 即使只是短暂的一次,但我们知道我们需要以某种形式进行输入,更新游戏的内部状态,最后将其渲染到屏幕上,并产生一些声音和/或振动 ...

  6. 产品经理,如何制定完美的产品策略?

    什么是产品策略? 策略是为了实现产品目标,而对产品逻辑不断调整的过程. 策略是线性的.动态的,强调的是连续的调整优化,不是静态的一劳永逸. 策略是产品的灵魂,稍微的改动就可能对用户产生巨大的影响.那么 ...

  7. android unity hook,Unity3d安卓游戏DLL动态调式与HOOK基础

    本帖最后由 xiaoxin520 于 2016-4-4 02:27 编辑 本文作者七少月,文章中很多观点和技术手段为本人原创,转载请注明出处,由于本人技术水平有限,不当之处,还请斧正. 前言: 由于本 ...

  8. Android游戏开发–游戏循环

    游戏循环是每个游戏的心跳. 到目前为止,我们仅使用了非常简单的一种(您可以在此处找到),无法控制我们更新游戏状态的速度或速度以及要渲染的帧. 概括地说,最基本的游戏循环是while循环,该循环一直执行 ...

  9. android_Android游戏开发–游戏循环

    android 游戏循环是每个游戏的心跳. 到目前为止,我们使用的是非常简单的游戏(您可以在此处找到),无法控制我们更新游戏状态的速度或速度以及要渲染的帧. 概括地说,最基本的游戏循环是while循环 ...

最新文章

  1. ITU-T Technical Paper: IP网络测量模型
  2. 莱比特矿池CEO江卓尔:BCH作为货币不需要新功能,但出于货币竞争的考虑需要
  3. 将用户添加至sudoers列表
  4. 华为 鸿蒙只是物联网,“鸿蒙”不只是手机系统,任正非:是为物联网所打造的系统...
  5. 注意指针修饰符的准确含义
  6. effective mysql之备份与恢复_Effective MySQL之备份与恢复
  7. 2025. 分割数组的最多方案数
  8. 1.阿里云RDS配置白名单,实例,外网地址,mysql数据库。
  9. 自定义日期输入控件-解决需要用户输入日期的麻烦控制
  10. elt和etl_ETL和ELT架构概述
  11. javaweb实训第三天下午——Web基础-Servlet交互JSP原理及运用
  12. 关于调试,很大的感触,请看下面的c程序
  13. 知识表示与计算机,两分钟了解人工智能中的“知识与知识表示”
  14. 记一次爆破六位数密码(图书馆系统登录)
  15. 转帖 分享代码自动生成
  16. Qt开发 — WindowType详解
  17. 字节跳动面经(2020春招)
  18. eSpeak TTS 中英文真人发音引擎
  19. 本地计算机架设http服务器,多维互联网(在本地电脑上架设web服务器软件)
  20. Win 10镜像下载和Win 10重装系统

热门文章

  1. p2p技术分类与发展方向
  2. handler相关学习(三)handler必背
  3. Jim Joseph加入Burson Cohn Wolfe,担任新设立的全球职位
  4. Xms、Xmx、MaxMetaspaceSize含义
  5. C语言实现strcpy和strcmp
  6. 分布式 和 集群 的区别
  7. 三、Qt常用容器之QList
  8. Altera 逻辑锁定
  9. 算完boxplot的四分位数以后,如何利用excel制作boxplot
  10. python爬虫爬取今日头条_python 简单爬取今日头条热点新闻(一)