找回密码
 立即注册
查看: 384|回复: 8

[UE4官方直播学习记录]虚幻C++进阶之路|大钊(二)

[复制链接]
发表于 2022-1-8 09:26 | 显示全部楼层 |阅读模式
接上篇

  • 反射-UHT
    ① 理解generated.h和gen.cpp
    ② 理解MODULENAME_API含义(用来做dll导出的,容易出错)
    ③ 掌握常用宏的含义和用法(反射的重要标记):UCLASS,USTRUCT,UENUM,UPROPERTY,GENERATED_BODY等
    ④ 清晰理解类型和对象的关系,ClassReference VS ObjectReference
         (类型引用 和 对象引用)


     ⑤ 掌握通过反射遍历对象属性、读取写入
     ⑥ 掌握通过反射遍历对象函数并调用的方式
     ⑦ 通过对象找类型,通过类型找对象
     ⑧ 理解“对象用类型描述,类型也是对象”
UE4反射机制概要

① 首先了解反射:反射是指在运行状态下,可以构造任意一个类的对象,可以了解任意一个对象所属的类,可以了解任意一个类的成员变量和方法,可以调用任意一个对象的属性和方法。(包括在编译时未确定的类或者对象)这种动态获取程序信息以及动态调用对象的功能称为反射。
② 支持反射的语言有Java、C#等等,但C++本身是不支持反射的,所以UE4在C++基础上搭建了一套自己的反射系统。通过反射,UE4可以实现序列化,GC(垃圾回收),网络复制,C++蓝图通信等重要功能。
③ 当一个头文件中include了“xxx.generated.h“,意味着这个头文件加入了反射系统。那些UPROPERTY,UFUNCTION之类的宏,也标记着这些方法属性等等加入了UE4的反射系统,加入了反射系统,UE4才能帮你做GC(垃圾回收),你才能实现蓝图C++通信等等很多功能。
UnealBuildTool和UnrealHeadTool可以看作是UE4实现反射系统的工具。
UBT通过扫描头文件,记录所有包含反射类型的modules(模块),当其中有头文件改变时,就会用UHT更新反射数据。UHT解析头文件,扫描标记,生成用于支持反射的C++代码。
(个人总结,参考某大佬的文章 https://zhuanlan.zhihu.com/p/60622181)


  • CoreUObject
    ① GC(垃圾回收):
    UE4采用了标记清扫的垃圾回收方式。从一个Root集合出发,遍历所有存在引用关系的对象。遍历完成后就可以标记出存在引用的和没有引用的了,然后清理掉不存在引用的对象。   
    GC方式可以类比C#,有UPROPERTY标记才能被引擎GC。
    UE4重载了new、delete关键字,不要使用。
    FGCObject : :AddReferencedObjects可以手动添加不希望被垃圾回收的UObject的硬引用。
    ② ClassDefaultObject(类默认对象):理解类型和对象实例化,模版
    理解ClassDefaults作为模版的作用
    理解ClassDefaultObject在序列化中的意义作用
    通过UClass : : GetDefaultObject可以获得ClassDefaultObject的信息
    ③Package:理解对象的相互组织方式
    对象可以包含子对象
    序列化时,把一系列对象用一个对象包起来,这一个对象叫Package
    Package也可以互相引用,根据对象相对路径
Which——虚幻C++中有哪些套路需要掌握?

  • 模块链接:几个常用属性.AddRange
    比如最近我要在C++中引用到NiagaraComponent,但却找不到头文件
    此时需要在项目的build.cs中添加模块链接



  • 创建Actor方法:ConstructorHelpers,CreateDefaultSubobject,SetupAttachment
  • GamePlay框架继承
    ① 尽量别在关卡蓝图写逻辑:个人认为那些不复用的,关卡自身的特殊逻辑,触发一些事件之类的还是写在关卡蓝图比较方便,比如我们在做的解谜游戏,每关都会有一些特殊的关卡设计。但如果做一个吃鸡类游戏,关卡蓝图中应该是很干净的。
    遵循引擎结构,善用GamePlay框架比如GameInstanse,GameMode,GameState,PlayerController等,继承使用,后期扩展和联机会十分友好。
  • C++与蓝图交互
    ① UPROPERTY UFUNCTION宏的使用,各种函数属性说明符BlueprintCallable,EditAnywhere等等。
    官方文档-函数说明符 官方文档-属性说明符
    ② C++基类写逻辑,蓝图继承然后可视化配置数据。这种方式易扩展高性能,十分舒服。
    ③ 善用函数库。
  • 事件绑定
    ① DELEGATE(委托),MULTICASTDELEGATE(多播),DYNAMIC(动态)
    ② 输入事件绑定:BindAxis,BindAction
    ③ 碰撞事件绑定:Hit,Overlap(AddDynamic)
    ④ Slate&UMG Event:SLATE_EVENT(FOnClicked,OnClicked)
    ⑤ 计时器:FTimerManager::SetTimer,ClearTimer
  • 引擎常用方法
    ① Engine/Class/Kismet中的各种库十分有用。
    ② Kismet/GamePlayStatics很常用,可以访问GamePlay的很多对象。
    ③ UKismetSystemLibrary,系统目录等功能。
    ④ UKismetMathLibrary,数学库。
Which——有哪些编码注意事项?

  • 用插件在项目间共享代码,动手编码前多思考架构
  • 变量类型尽量偏向抽象基类,比如声明一个粒子的引用时,使用UFXSystemComponent而不是ParticleSystemComponent或者NiagaraSystemComponent,可以适应多变的情况。
  • Include头文件时,请Include What You Use(只包含使用到的头文件),加快编译速度
  • 善用C++前置声明,加快编译
  • 善用蓝图函数库
  • C++代码里不要做数据配置。 尝试数据驱动或者在蓝图原型中配置数据。
  • 没有C++基类的蓝图类,可以重新设置基类,注意先备份。
  • 重构了C++基类名字,导致蓝图找不到父类?可以用CoreRedirects修复。
  • 尽量不修改引擎代码,如果修改,做好注释或记录
Which——虚幻C++有哪些学习难点?

  • 数据结构与算法,操作系统,多线程
  • 数学物理相关知识例如线性代数等
  • 渲染,动画,AI等游戏开发知识
  • 足够的项目开发经验才能设计出强壮的代码框架
  • 理解不了别人的代码

6.How——如何学习虚幻C++?

  • 学会模仿代码比如模版项目,引擎源码,社区项目等
  • 模仿的基础上尝试修改
  • 学会总结与记录
  • 积累有用的代码功能块,对于概念,尝试用思维导图加深理解
  • 必须要项目实战
C++与蓝图的合适比例

  • 根据80/20原则,20%核心用C++,80%表层用蓝图(根据项目类型和个人水平而定)
  • 大概规则:
    偏向引擎底层,偏向性能热点,偏向稳定的,采用C++
    偏向表现层,偏向经常操作的,偏向多变的,采用蓝图
三、虚幻引擎源码剖析经验分享

1.源码剖析方法论

  • 时空观
    ① 时:注重时间上的先后,观察函数的调用流程,事件的触发时机
    ② 空:注重数据的吞吐转换,观察信息的采集,数据的加工消化利用
    ③ 时空的交互,组成了有机的功能架构支撑,调度起资源,启动内循环,响应外部刺激
  • 信息论
    ① 最小信息原则=依赖最少=越稳定
    ② 信息本质也是能量,只有掌握足够信息,才足以实现某些功能
    ③ 数据是信息,代码结构是信息,项目协作方式也是信息
  • 保持谦逊但不迷信
    ① 大部分认为引擎代码不够好的时候,其实都是自己的问题。
    ② 引擎开发人员也会犯错,有错很正常。
    ③ 引擎存在某些历史遗留问题,开发人员也没办法,不要太苛责。
  • 耐心比好奇心更重要
2.源码剖析工具

  • 工具越简单越好,专注核心内容,别浪费时间调整格式。
    ① 只用VisualStudio阅读源码,额外的都是负担。
    ② 放弃UML图系列工具,只取其思想,放弃其形式。
    ③ 完全理解的内容,才需要画图加深理解。
    ⑤ 思维导图是个不错的选择。
    ⑥ 写文章可以尝试用Markdown码字,Processon画流程图
  • 调试过程
    ① 开Debug配置编译源码(此篇文章中有配置选项说明 InsideUE4基础概念)
    ② 边调试边记录
    ③ 在引擎源码内添加Debug输出,可以确定数据内容先后顺序
    ④ 以主线为主,支线可以先放放
  • 用于寻找的工具
    ① WidgetReflector定位代码块



② VisualAssistX查找所有引用调用(正版很贵很贵很贵)
③ VisualStudio字符串查找
④ Everything工具定位文件
⑤ 开Debug断点查事件调用
3.注意事项

  • 能找到办法调用就不要拷贝代码
  • 事先理解各模块对象的组织关系,有助于找到调用的代码
  • 别在Runtime下调用Editor代码,不合法且费劲
  • 找到目录代码块之后,注意输入输出,小心内部依赖
有任何问题请评论或私信,感谢关注评论点赞收藏!

本帖子中包含更多资源

您需要 登录 才可以下载或查看,没有账号?立即注册

×
发表于 2022-1-8 09:30 | 显示全部楼层
作者咋这么牛逼啊?
发表于 2022-1-8 09:32 | 显示全部楼层
?上一秒你还在感谢作者
发表于 2022-1-8 09:32 | 显示全部楼层
“UE4重载了new、delete关键字,不要使用。”这是针对UObject来说的吧?自定义类型还是可以使用new和delete的吧(虽然使用智能指针更为提倡)。
发表于 2022-1-8 09:38 | 显示全部楼层
是的 感谢补充
发表于 2022-1-8 09:48 | 显示全部楼层
我只是确认一下,因为我自己写插件经常还是会用new哈哈
发表于 2022-1-8 09:53 | 显示全部楼层
感谢感谢,3个小时的精华啊,本来还想从头听到尾搬一遍呢。
发表于 2022-1-8 09:55 | 显示全部楼层
还是带着大钊老师的口音更有感觉
发表于 2022-1-8 10:01 | 显示全部楼层
“UE4重载了new、delete关键字,不要使用。”麻烦请问一下,对于package也是一样吗?
懒得打字嘛,点击右侧快捷回复 【右侧内容,后台自定义】
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

小黑屋|手机版|Unity开发者联盟 ( 粤ICP备20003399号 )

GMT+8, 2024-11-25 12:00 , Processed in 0.103515 second(s), 26 queries .

Powered by Discuz! X3.5 Licensed

© 2001-2024 Discuz! Team.

快速回复 返回顶部 返回列表