Unity3D引擎框架及用户接口调用方式相关分析及汇总

发表于2016-07-19
评论0 5.2k浏览

分析目的
  目前外网3D手游绝大部基于Unity3D引擎进行开发,Unity3D引擎属于商业引擎,引擎整理框架的运行机制较为神秘,本文介绍Unity引擎框架、对象组织方式、用户接口与引擎交互方式等原理,通过本文的分析和介绍可了解Unity3D框架中大致执行原理。
 
实现原理
  Unity引擎作为目前最为主流的3D游戏开发引擎,游戏平台移植性非常好,本文从整体分析Unity引擎相关结构,分为:Unity关键类继承关系、用户实现接口与引擎的调用机制、Unity引擎顶层框架及帧更新机制、对象组织方式、Unity引擎的安全风险。

一、Unity游戏关键类继承关系
  Unity3D引擎为用户提供方便快捷的开发工具,用户可在Unity提供的MonoDevelop-Unity开发工具中新建基于MonoBehaviour行为类,对应创建框如下所示:


      

将定NameTest,创建之后生成的代码如下图所示:


           

  上图是Unity游戏中最为常见代码样式,其中用户定义的类大都继承引擎提供的MonoBehaviour类,用户定位的类整体继承关系如下图所示:

                 

  用户定义的每一个类在引擎中都属于一个组件,引擎中每个Component类定义了GameObject类型的对象,用于申明当前组件所属的游戏对象。Unity引擎的游戏中,用户定义的类继承关系较为统一,都由引擎负责管理和更新,上图定义的Test对象中有StartUpdate两个默认接口,下一章节见将介绍Unity引擎用户实现的接口调用方式。

二、用户实现的接口与引擎调用关系
  Unity3D引擎为游戏开发者提供了脚本语言(例如:C#、Javascript)编写代码,基于Unity引擎的开发者通用可通过如下如下几种方式实现接口的调用:
1)基于引擎帧更新机制调用用户实现的接口。
2)基于引擎的消息事件响应机制调用用户接口。
3)引擎的延迟调用机制。
4)其他直接调用方式

下面将详细介绍几种机制调用机制进行详细的分析介绍。
1、基于引擎帧更新机制的用户接口调用
  创建Unity引擎的C#脚本文件,会默认为类生成StartUpdate函数,其中Start函数仅在Update函数第一次调用时会被引擎调用,用户通过Start实现初始化操作,类似于类的构造函数。
Unity引擎为用户提供了多种帧更新操作,例如常用的三种更新操作为:Update、FixedUpdate、LateUpdate,三种Update调用机制不相同,三种函数调用机制如下:
Update:引擎会在每帧更新的过程中遍历对象并更新该组件的Update函数。
FixedUpdate:引擎以固定时间调用组件的FixedUpdate函数。
LateUpdate:在Update函数调用之后调用,通过该功能可调整脚本执行的顺序,例如:当无敌在Update里移动时,跟随物体的相机可在LateUpdate里实现镜头移动。
用户定义组件对象默认继承MonoBehaviour,用户实现的每帧更新Update函数于引擎的PlayerLoop函数调用(该函数于Player.cpp实现),其中GetBehaviourManager()是获取管理Update方式每帧更新的调用方法,其中GetBehaviourManager().update()函数及所属类的GetBehaviourManager().update()函数内部由CommonUpdate模版实现。用户实现的FixedUpdate属于固定时间的调用方式,对应在PlayerLoop函数中调用。GetTimeManager().StepFixedTime()函数会判断是否需要处理固定时间的相关操作,例如用户定义的FixedUpdate函数更新逻辑,所有的组件Update调用之后才调用LateUpdate函数。

2、基于引擎消息事件的调用机制
  Unity引擎提供给用户感知某些消息类事件的感知,例如某游戏的EntityCollider.cs文件中实现了EntityCollider::OntriggerEnter方法,对应代码如下图所示:

         

  该类函数由用户实现,上图红框函数在引擎中与消息进行绑定,其中OnTriggerEnter为用户感知碰撞探测相关事件,OnTriggerEnter函数绑定了kEnterTrigger函数,在PhysicsManager::ProcesssRecordedreports函数内部调用,在判断当前MessageID为kEnterTrigger之后,已消息方式调用SendMessage函数让引擎调用用户实现的OnTriggerEnter接口。其中PhysicsManager::ProcesssRecordedreports函数由PhysicsManager::FixedUpdate调用,消息处理机制是引擎以固定时间的方式在PhysicsManager类的FixedUpdate方法中不断调用实现。

3、基于延迟调用机制及其他方式
1)延迟调用方式
  Unity为用户提供了延迟调用某方法,对应通过Invoke和InvokeRepeating 函数实现,其中Invoke和InvokeRepeat接口定义如下:
function Invoke (methodName : string, time : float) : void
function InvokeRepeating (methodName : string, time : float, repeatRate : float) : void
Invoke为延迟调用一次,InvokeRepeating 为延迟调用多次,延迟调用通过引擎的InvokeDelayed函数实现,延迟调用机制较为简单,延迟的时间、重复调用的次数都由用户控制。
2)其他机制
  其他机制包括用户定义的C#函数之间调用,该类调用方式与C++函数调用方式类似,不在进行详细阐述。

三、Unity整理框架及帧更新机制
  Unity引擎将所有重要事件于主线程中实现,如帧更新逻辑、渲染逻辑、碰撞检测逻辑等,Unity引擎初始化及运行帧更新相关执行流程如下图所示:

                           

  其中UpdateScene负责更新游戏场景中所有帧更新时间。PlayerLoop函数属于每帧更细都会调用,该函数负责处理游戏中所有组件的Update、及消息事件相应处理。
  Unity引擎会以一定间隔时间不断更新游戏场景中所有相关事件,每次需要计算下一次帧更新所需的间隔时间,对应时间计算在MainMessageLoop函数实现,通过Sleep方式将执行权切换给其他线程,防止出现CPU 100%的情况。

四、Unity引擎对象链表组织方式
  每个游戏都会通过某种方式存储场景中的所有对象,Unity引擎的场景对象通过GameObjectManager进行管理,GameObjectManager通过STLList结构存储了游戏场景中所有对象,通过遍历List链表便可获取到游戏场景中所有对象,Unity通过GameObject::FindGameObjectWithTag函数可通过传入对象的标识从而获取到对象指针,函数通过遍历List链表的所有信息查找所需的对象。每个GameObject对象都包含了Tag字段,该字段用于区分不同的对象,Unity引擎提供的游戏开发工具中可提供Tag的标签设置,对应设置界面如下图所示:

                

玩家可根据具体需求定义所需要的对象标签,也可选用默认的标签。
 
总结
  Unity3D引擎属于3D手游开发首选引擎,Unity3D引擎以回调的方式处理用户开发的游戏逻辑事件,主要集中于引擎每帧回调游戏Update、游戏基于消息事件调用游戏逻辑函数、引擎以延迟方式调用游戏事件。通过本文的分析和介绍,可了解Unity引擎整体框架、用户接口于引擎交互机制、引擎顶层帧更新机制及对象链表的组织,对Unity引擎有更加直观的认识。

如社区发表内容存在侵权行为,您可以点击这里查看侵权投诉指引