热门标签 | HotTags
当前位置:  开发笔记 > 编程语言 > 正文

虚幻4随笔三从UE3到UE4

笔者有幸参与过两个UE3项目,完全不同的使用方法,总共用了5、6年。引擎学习最好还是能参与项目,自己看的话往往容易纠结到一些细节上去,而引擎之所以是引擎,重要的恰恰是在容易被人忽视的工


笔者有幸参与过两个UE3项目,完全不同的使用方法,总共用了5、6年。引擎学习最好还是能参与项目,自己看的话往往容易纠结到一些细节上去,而引擎之所以是引擎,重要的恰恰是在容易被人忽视的工作流上。单从细节上看,UE3的代码很多地方并不完美,甚至有些奇怪,但是一旦做到工作流上,就会发现整个UE3工作流的强大之处。
先回顾一下UE3系统的一些结构要点,权当做个记录,看看UE4在这些方面有什么不同,作为我们接下来读码的突破口。
如果真心想要学习这个引擎,最好还是能用它来做做项目,项目不分大小,只论完整程度,笔者短时间内看来是没机会了。



1、BuildTools
UE4除了工具和插件外,本体不分工程了,UE3的核心部分最后分了Core、Engine、Editor、WinDrv、Network、Renderer等十数个工程,UE4就一个UE4工程。但工程归工程,编译时还是分得很开的。


而且这个工程猜测是靠BuildTools来生成出来的(一开始那个bat)。看起来,散落在各个文件夹下的.cs文件就像CMakeList.txt那样,它们才是整个工程的组织核心。
事实上从UE3时代,就可以完全脱离Visual Studio IDE来工作了,UE3的工程本身都已经不再是典型的VC工程,代码编完后,实际上最后执行的是Build.bat、调用UnrealBuildTools.exe来编译,所以要改工程设置,也是需要去修改UnrealBuildTools工程的。
** 估计,如果要改工程组织结构,增加文件什么的,也需要维护这个.cs文件吧。这个可能得等做做才知道了。
不过应该可以看出来,UE4这里是为了支持项目和引擎分离而进行的。



2、Core
个人观点,UE3的Core重点是下面几个部分:
作为整个虚幻构架基础的UObject和由一大堆宏和各种Classes.h这套组织结构反射系统——围绕它的包括GC、UObject与UnrealScript的互操作性、与编辑器的互操作性、自动序列化、对象克隆等。这个非常重要,整个虚幻体系的核心就是这一套东西,如果前面不注意的话,后面迟早会在这里栽点跟头。


序列化和统一具名访问:ULinkLoader,起这个名字可能主要是因为加载的时候,它会自动分析Object的引用链,并且根据需要继续往下加载。另外,所有虚幻的Object都会有自己独一无二的具名路径,例如xxx.umap:persistentLevel.Pawn_0,xx.Material.Material_0,任何时候,只要使用LoadObject、FindObject并传入这些名字,就可以访问到对应的对象。这个在编辑器的维护中是相当方便的一个底层特性。甚至,这个具名路径还可以访问到脚本中的类、内置模板资源等等。


MakeCommandlet和UC脚本核心:Core中间编码了整个Unreal Script的编译和运行时环境。Unreal Script编译过程中会生成相应工程的Unreal Script/C++互操作文件:xClasses.h以及一堆自动生成的方法和调用。编译后的结果是.u文件,其实同时就是跟.upk资源文件一样的格式——虚幻2不清楚,但至少从虚幻3时代开始,资源和脚本就被当作是同一个东西,脚本是可执行的资源,资源是不可执行的脚本。另外与此相关的就是一套调试器——很多人用了半天虚幻3却不知道虚幻脚本是可以调试的……AutoDebug命令行或者ToggleDebugger指令搜一下,印象中调试器的核心接口是基于UDebuggerCore还是UDebuggerInterface这个类。VS装nFringe插件后、或者自带的UDE都可以对脚本进行调试。


状态机:脚本的特殊语法,状态机是在脚本类内部的概念,每个状态可以重载脚本类某些函数的实现,这样当状态切换到这个状态的时候,就只是执行状态内的函数而非脚本类的函数本身。Actor和Controller里大量用到。


Latent:脚本的特殊语法,基本类似于不通过连线的Kismet,latent类似于Erlang这样的Coroutine语言,每个语句都是步骤而非过程,步骤可能会花很多帧去执行,执行完毕后接着进行下个步骤,传统语言的过程只能当前帧执行完毕。


其它就是一系列的数学库、内存管理、辅助函数。内存管理比较有意思,一开始看总觉得问题较大,当时组里的内存专家Aman Jiang老师实际打出来报告后发现这块儿管的还是很不错的,碎片率远低于我们的预期。



3、Engine
相当庞大的集合,个人观点,重点在于:
Actor-Component体系:组件化结构的虚幻版,组件化现在应该是大多数引擎的标配了吧?这块儿可以说中规中矩,主要组件还是得花心思去看看,否则极易在接口调用顺序乱掉的情况下发生问题。渲染器与游戏上层逻辑通过Component来接口,提供新的渲染技术后,只需要做一个对应的Component就可以了——SpeedTree什么的就是这么集成进来的。


Game-Player-Controller体系:Game Mode决定了当前关卡的游戏玩法,一个关卡可以有不同的游戏玩法——对于FPS你可以想象虚幻竞技场中的很多地图都同时支持Free for all、夺旗、Team计分。对于网络游戏,你可以想象一个关卡资源可以用来做战场、也可以用来做副本。Player是所有IO的总入口,一般一个游戏只有一个Player,就是Local Player。主机游戏可以设计同时存在两个Player的场合,可以用分屏显示来分离各自的IO。进入地图后,会针对当前地图生成Controller,来实际从Player截获输入和部分输出操作,并真正影响到游戏中。相应的概念还包括View(实际上的摄像机)、ClientViewport(游戏和编辑器窗口)。


Controller-Pawn体系:Pawn是可以被Controller控制的东西,Controller把IO和UI消息转化为对Pawn的操作,通知Pawn完成其功能,并把这些功能执行过程反馈给IO和UI。在游戏中可以切换Controller内部的不同状态,例如根据Pawn是在走还是在爬墙,把输入消息转化为对Pawn不同的指令。还可以切换Controller,比如进载具了,Controller一换就Ok。甚至技能中也可以切换Controller,比较经典的例子就是虚幻竞技场3里的榴弹炮:普通架起来的状态下打出的是一般炮弹,炮弹飞行过程中鼠标可以一直控制其方向,右键可以把这个炮弹展开使其定位在空中,然后你的视角一直停留在这个炮弹上,鼠标变成在地面选择一个区域,火炮变成一门发射榴散弹的大杀器,把致命散弹砸向这个区域。笔者接触过不少游戏的游戏系统了——不幸的是这个流程很少有系统能够不加大改地实现。AI也是一种Controller,操纵的是Bot这个特殊的Pawn,这块儿有兴趣也可以研究一下。


World-Level-Actor体系:World里存一堆Level,Level里存一堆Actor, Build后的光照跟Level走,Level是关卡部分的资源单位。但场景图根是World里的Hash,虚幻3里是个八叉树实现。World里实现了基本的场景功能,角色的走跑、悬崖边缘的检测、走到碰撞体前被挡住、碰撞体位置变化时导致自己上面放置的其它碰撞体变化……你如果有自己的场景需求,可以修改World里面的这个部分。注意,在虚幻3里场景和物理虽然有关,但是本质上还是分离的,引擎提供了默认的整合方式,但你可以在Actor里重新控制这种整合。


资源体系:没什么好说的,Material、Texture、各种Mesh、Particle。Material连线球很赞,但是跟渲染Stage有较深的关联,笔者试图做过一个自以为比他更好的,跟Stage可以一定程度脱耦的材质连线球系统——但是最终发现材质这东西根本上还是离不开渲染Stage,什么都想控制的结局一定是什么都控制不过来。
渲染体系:就不说什么了吧,Deferred Lighting的Stage体系,网上的文章海了去了,做图形的这个早就抛脑后了吧。最近一两年的版本支持了Deferred Shading。这套Stage的低端化替换还是很方便的——毕竟现在需要考虑到游戏可能更多是会在intel HD 3000/4000这种显卡上跑的可能性了。



4、UnrealEd
编辑器……怎么说呢,这个没法按体系来了,太多了,有些精品也有些糟粕,反正编辑器这东西,没法说,需要扩展的时候自己去改吧。
注意属性编辑器是如何发挥反射的强大效力的。
有些细节问题,实际做了可能会遇到:拷贝对象时,有些属性是引用的(一般的Object属性不加任何描述),有些是复制的(editinlinenew、instance和duplicate),有些是舍弃的(transient)。还有就是虚幻比较喜欢用Prototype + Clone的方式来实现Template-Instance这种需求,典型的例子是Animation Tree和Prefab,实例都是直接从资源拷贝出来的。主要是因为UE3的反射外围有一个比较强大的Clone系统,但是前提是您得对刚刚列举的那些关键字比较熟悉,否则为这些系统扩展时就比较容易遇到问题。
多说一句:编辑器选物体用的是把物体的ID渲到一张Render Target上再去这个Render Target上查找鼠标点Id的做法,叫HitProxy,如果你的游戏想支持像素点选,可以参考这个东西,很容易就能把这个Stage集成到游戏Stage里。



5、其他工程
就没什么好说的了:
渲染器:Renderer,DX9、DX10、DX11、OpenGL的实现都有,DX10只有一个版本昙花一现。
平台库:以XXXDrv为名,例如WinDrv。主要提供平台方法,没什么好说的。
网络库:IpDrv、Channel什么的,也没什么好说的。



网游的开发者很喜欢自己构造上层,我参与的第一个UE项目就是这么做的,实际上最后做出来的上层后来看来比虚幻的整个上层体系差的太远。第二个项目笔者就一直推动着在虚幻框架上的小修小改。最后能实现什么呢?能实现在编辑器里根服务器通信,编辑器调整完Kismet连线图、资源、布怪点后,不用退出,直接就可以启动开发服务器,然后在编辑器内测试刚刚自己做的东西对不对,可惜因为资金原因没做下去,两年前这个级别的工具集成,不知道有多少人做到了?至少我现在在这个项目里还没能推广到,也不可能推广到那个程度(笔者鼻子翘起来了~*^_^*)。不过未来不需要再弄了——看看虚幻4的Blueprint,可以考虑这个级别的集成了。

笔者一直认为,虚幻3强大的地方不在于他的图形,而是在于这套强大而稳固的结构和迅速的工作流,而当你握这套结构和工作流后,笔者发现所有引擎在自己的面前索然无味,图形虽然还在追求,但已经退居次席了,而自己重新去做引擎的冲动则不断降低,直至完全消失。
用虚幻一定要首先明白一个原则,就是这是个解决方案式引擎,不是OGRE那样的图形工具库,所以你的所有改动一定要符合虚幻的基本结构假设,否则你只是在给自己找麻烦。但是,相信我,符合这些基本的结构假设一点不会让你的自由度降低,你的控制能力把控能力还是相当强的——不信你看,笔者上面列举的框架部分,有哪个是会影响你的发挥的?M——World-Actor、V——Player、C——Controller,哪一环是可以省略的?当然,如果您的体系结构设计的比这个还好,那真的很恭喜您了,一山更比一山高,笔者只能感叹于自己的时运不济了……

这两天还是在看例子,看几个Blueprint的例子,顺便回想一下UE3的那些事儿。最近的紧张局面可能会延续到4月中旬,届时才有可能有更多时间来看UE4。目前感觉变化还是挺大的,不过,喜在框架方面的改动似乎很有限。
从另一个方面,也证明了UE3的这套游戏上层逻辑框架,是多么地稳固和强大。


推荐阅读
  • 拥抱Android Design Support Library新变化(导航视图、悬浮ActionBar)
    转载请注明明桑AndroidAndroid5.0Loollipop作为Android最重要的版本之一,为我们带来了全新的界面风格和设计语言。看起来很受欢迎࿰ ... [详细]
  • 本文介绍了RPC框架Thrift的安装环境变量配置与第一个实例,讲解了RPC的概念以及如何解决跨语言、c++客户端、web服务端、远程调用等需求。Thrift开发方便上手快,性能和稳定性也不错,适合初学者学习和使用。 ... [详细]
  • Java和JavaScript是什么关系?java跟javaScript都是编程语言,只是java跟javaScript没有什么太大关系,一个是脚本语言(前端语言),一个是面向对象 ... [详细]
  • Oracle seg,V$TEMPSEG_USAGE与Oracle排序的关系及使用方法
    本文介绍了Oracle seg,V$TEMPSEG_USAGE与Oracle排序之间的关系,V$TEMPSEG_USAGE是V_$SORT_USAGE的同义词,通过查询dba_objects和dba_synonyms视图可以了解到它们的详细信息。同时,还探讨了V$TEMPSEG_USAGE的使用方法。 ... [详细]
  • 本文介绍了Python爬虫技术基础篇面向对象高级编程(中)中的多重继承概念。通过继承,子类可以扩展父类的功能。文章以动物类层次的设计为例,讨论了按照不同分类方式设计类层次的复杂性和多重继承的优势。最后给出了哺乳动物和鸟类的设计示例,以及能跑、能飞、宠物类和非宠物类的增加对类数量的影响。 ... [详细]
  • 生成式对抗网络模型综述摘要生成式对抗网络模型(GAN)是基于深度学习的一种强大的生成模型,可以应用于计算机视觉、自然语言处理、半监督学习等重要领域。生成式对抗网络 ... [详细]
  • 在Android开发中,使用Picasso库可以实现对网络图片的等比例缩放。本文介绍了使用Picasso库进行图片缩放的方法,并提供了具体的代码实现。通过获取图片的宽高,计算目标宽度和高度,并创建新图实现等比例缩放。 ... [详细]
  • CSS3选择器的使用方法详解,提高Web开发效率和精准度
    本文详细介绍了CSS3新增的选择器方法,包括属性选择器的使用。通过CSS3选择器,可以提高Web开发的效率和精准度,使得查找元素更加方便和快捷。同时,本文还对属性选择器的各种用法进行了详细解释,并给出了相应的代码示例。通过学习本文,读者可以更好地掌握CSS3选择器的使用方法,提升自己的Web开发能力。 ... [详细]
  • android listview OnItemClickListener失效原因
    最近在做listview时发现OnItemClickListener失效的问题,经过查找发现是因为button的原因。不仅listitem中存在button会影响OnItemClickListener事件的失效,还会导致单击后listview每个item的背景改变,使得item中的所有有关焦点的事件都失效。本文给出了一个范例来说明这种情况,并提供了解决方法。 ... [详细]
  • 本文介绍了C#中生成随机数的三种方法,并分析了其中存在的问题。首先介绍了使用Random类生成随机数的默认方法,但在高并发情况下可能会出现重复的情况。接着通过循环生成了一系列随机数,进一步突显了这个问题。文章指出,随机数生成在任何编程语言中都是必备的功能,但Random类生成的随机数并不可靠。最后,提出了需要寻找其他可靠的随机数生成方法的建议。 ... [详细]
  • Android Studio Bumblebee | 2021.1.1(大黄蜂版本使用介绍)
    本文介绍了Android Studio Bumblebee | 2021.1.1(大黄蜂版本)的使用方法和相关知识,包括Gradle的介绍、设备管理器的配置、无线调试、新版本问题等内容。同时还提供了更新版本的下载地址和启动页面截图。 ... [详细]
  • Google Play推出全新的应用内评价API,帮助开发者获取更多优质用户反馈。用户每天在Google Play上发表数百万条评论,这有助于开发者了解用户喜好和改进需求。开发者可以选择在适当的时间请求用户撰写评论,以获得全面而有用的反馈。全新应用内评价功能让用户无需返回应用详情页面即可发表评论,提升用户体验。 ... [详细]
  • 闭包一直是Java社区中争论不断的话题,很多语言都支持闭包这个语言特性,闭包定义了一个依赖于外部环境的自由变量的函数,这个函数能够访问外部环境的变量。本文以JavaScript的一个闭包为例,介绍了闭包的定义和特性。 ... [详细]
  • Java学习笔记之面向对象编程(OOP)
    本文介绍了Java学习笔记中的面向对象编程(OOP)内容,包括OOP的三大特性(封装、继承、多态)和五大原则(单一职责原则、开放封闭原则、里式替换原则、依赖倒置原则)。通过学习OOP,可以提高代码复用性、拓展性和安全性。 ... [详细]
  • MPLS VP恩 后门链路shamlink实验及配置步骤
    本文介绍了MPLS VP恩 后门链路shamlink的实验步骤及配置过程,包括拓扑、CE1、PE1、P1、P2、PE2和CE2的配置。详细讲解了shamlink实验的目的和操作步骤,帮助读者理解和实践该技术。 ... [详细]
author-avatar
兔女郎不会吧
这个家伙很懒,什么也没留下!
PHP1.CN | 中国最专业的PHP中文社区 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved | 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有