1、什么是MetaData
答:描述数据的数据,目的是对数据进行管理,包括监控数据质量,数据流向,业务分析等.比如ETL Job的定义,日志等,再比如数据仓库主题,度量,维度的定义等.
2,在做陷阱的时候,尖刺要从陷阱中升起和下降,由于缓慢上升要用timeline,其中有两个连接,play和Playe from start,区别
(1)最初的想法是拿到一百个尖刺数组,在foreachloop循环中调用timeline,对尖刺的worldLocation进行改变,发现,不对,好像是timeline是每一帧的执行时间
应该先调用timeline,然后再循环,也就是说先执行渐变在for循环,这个渐变能改变到每个for循环中
(2)Timeline要连接到Play from Start 而不是Play
(3)执行结束后延迟2秒调用尖刺上升函数,让它不断上升下降循环,这里执行结束时从timeline的Finished出来,而不是循环的Completed出来,这里要注意,但是不知道原因是什么。
3、UE4 命名约定
- 模版类以T作为前缀,比如TArray,TMap,TSet
- UObject派生类都以U前缀
- AActor派生类都以A前缀
- SWidget派生类都以S前缀
- 抽象接口以I前缀
- 枚举以E开头
- bool变量以b前缀,如bPendingDestruction
- 其他的大部分以F开头,如FString,FName
4、
UE4实现了自己的一套编译系统,否则我们就得接受各个平台再单独配置一套项目之苦了。
这套工具的编译流程结果,简单来说,就是你在VS里的运行,背后会运行UE4的一些命令行工具来完成编译,其他最重要的两个组件:
- UnrealBuildTool(UBT,C#):UE4的自定义工具,来编译UE4的逐个模块并处理依赖等。我们编写的Target.cs,Build.cs都是为这个工具服务的。
- UnrealHeaderTool (UHT,C++):UE4的C++代码解析生成工具,我们在代码里写的那些宏UCLASS等和#include "*.generated.h"都为UHT提供了信息来生成相应的C++反射代码。
一般来说,UBT会先调用UHT会先负责解析一遍C++代码,生成相应其他代码。然后开始调用平台特定的编译工具(VisualStudio,LLVM)来编译各个模块。最后启动Editor或者是Game.
5、摘自:https://www.cnblogs.com/shilinnpu/p/8182288.html
C++ typedef typename 作用
C++的一些语法让人看着费解,其中就有:
typedef typename std::vector<T>::size_type size_type;
详见《C++ Primer》(第五版)P584
有些不懂的语法有时候虽然知道大概是什么意思,忽略一下就过了其实,不过心里老是膈应,就刨根问底一次吧。vector::size_type
明白上述语法,首先要先看清vector::size_type
的意思。参考《STL源码剖析》不难发现,其实:
template <class T,class Alloc=alloc>
class vector{
public:
//...
typedef size_t size_type;
//...
};
这样就看得很清晰了,vector::size_type
是vector
的嵌套类型定义,其实际等价于 size_t
类型。
也就是说:
vector<int>::size_type ssize;
//就等价于
size_t ssize;
为什么使用typename关键字
那么问题来了,为什么要加上typename关键字?
typedef std::vector<T>::size_type size_type;//why not?
实际上,模板类型在实例化之前,编译器并不知道vector<T>::size_type
是什么东西,事实上一共有三种可能:
静态数据成员
静态成员函数
嵌套类型那么此时
typename
的作用就在此时体现出来了——定义就不再模棱两可。总结
所以根据上述两条分析,
typedef typename std::vector<T>::size_type size_type;
语句的真是面目是: typedef
创建了存在类型的别名,而typename
告诉编译器std::vector<T>::size_type
是一个类型而不是一个成员。
6、typedef unsigned char uint8; //定义可移植的无符号8位整数关键字 这句话其中typedef是什么意思?
typedef就是做类型定义,为一种数据类型定义一个新名字。目的一般有两个,一个是给变量一个易记且意义明确的新名字,另一个是简化一些比较复杂的类型声明。比如typedef unsigned char uint8;就是用uint8来代替unsigned char,这样以后声明变量就可以用uint8 c;即方便又好记好理解。
7、UE4蓝图碰撞检测解析
https://blog.csdn.net/u012999985/article/details/51113853
8 问:vector的实现与增长
vector是stl提供的动态数组,想了解他就要从他的特性开始分析。首先,他是一个模板类,意味着可以存放各种类型的元素,同时他也是一个数组,存储是连续的。
内存分配:常规的数组必须在定义的时候就分配好固定的大小,而vector可以动态的改变,也就说明他可以动态的申请与释放内存。我们要知道,频繁的申请与释放内存对程序的效率影响是非常大的,因为如果当前地址空间不够用的话,就需要重新找一块更大的空间来装数据,再把数据全部都拷贝过去。所以vector为了达到比较好的效果,在添加元素的时候会多申请一定大小的内存,从而减少内存分配的次数。capacity()返回的就是包括缓冲区在内的空间大小,而size()返回的就是当前实际使用的空间大小。如果想主动的提前分配内存,可以使用reserve(n),会强制重新分配一次内存,超出实际使用的部分就会成为缓存区。如果想直接构造出长度为n的动态数组可以使用resize(n),实际分配的空间肯定要比n大,不过如果n比当前size小的话,大于size的数据都会被清空,如果比capacity还大的话就会重新执行一次内存分配。
关于内存释放,如果只是简单的调用 clear()全部清空数据,erase()清空部分数据 都只是单纯的清空里面的数据并不会释放掉。默认只会在调用vector的析构函数的时候才会真正释放空间,所以如果想强制释放那就新建一个空的vector,然后对这个vector使用swap讲内存交换,那么原来的vector就会释放,新的vector呢?
另外,由于涉及到模板,也就会涉及到迭代器,凡是重新申请过内存,插入删除数据的,迭代器都会失效,理解上也很容易就是指针可能指向的不是你原来的那个位置了。
摘自:https://blog.csdn.net/u012999985/article/details/78359151
9、在c++中写一个可以一直旋转的物体
(1)在蓝图中右键new c++ class,继承actor
(2)在蓝图中需要可调整旋转速度,因此在c++中
在Actor的构造函数中创建出SceneComponent组件和staticMeshComponent组件,将SceneComponent设置为RootComponent,再将staticMeshComponent绑定到RootComponent上。这里CreateDefaultSubobject是创建一个子Component
在tick中让它旋转
在蓝图中会看到
10、UE4的反射
C++本身并不支持任何的反射形式,所以虚幻引擎使用自身的一套系统来收集、查询和管理C++相关的类、结构体、函数、成员变量以及枚举器等信息。
反射系统是可以选择性加入的,你需要事先标记那些你想要被反射系统访问的任何类型和属性,(UHT)
工具将会在你编译项目的时候收集这些信息。
#include "FileName.generated.h"
要标记一个包含反射类型的头文件,需要在文件的顶部添加如上代码,让UHT
工具知道考虑这个文件,“.generate.h”文件在每一个类的声明前面都会被包含到对应的头文件里面。(这也是官方建议我们要用编辑器来创建类的原因,他们并不是常规的C++类)而“.generate.cpp”对于一整个项目只会有一个。这两种文件可以说是反射系统的关键所在,他们是通过Unreal Build Tool(UBT) 和UnrealHeaderTool(UHT)来生成的。.generate.h”里面是宏,而且包含一个非常庞大的宏,这个宏把所有和反射相关的方法(包括定义)和结构体连接到一起。而“.generate.cpp”里面是许多的函数定义,UnrealHeaderTool根据你在头文件里面使用的宏(UFUNCTION等)自动的生成这个文件,所以这个文件并不需要你去修改,也不允许修改。UBT属性通过扫描头文件,记录任何至少有一个反射类型的头文件的模块。如果其中任意一个头文件从上一次编译起发生了变化,那么 UHT就会被调用来利用和更新反射数据。UHT分析头文件,创建一系列反射数据,并且生成包含反射数据的C++代码(也就是“.generate.cpp”)以及各种辅助函数与thunk函数(“.generate.h”)
在UE4里面, 基本上所有的游戏工程的类都需要用到反射。比如,你用编辑器新建一个类,类的前面会自动添加UCLASS();新建一个结构体,需要使用USTRUCT();新建一个枚举变量,需要在前面声明UENUM();在类的里面,也必须要加上GENERATED_UCLASS_BODY()才行。
如果你想让你的变量能显示在编辑器里面,想让你的函数可以被蓝图调用或者通过让这个函数实现RPC网络通信功能,或者你想让你的变量被系统自动的回收,这些都离不开反射系统以及这些宏定义。
摘自(https://blog.csdn.net/u012999985/article/details/52902065)
FindFunction
函数
在UE4中提供了FindFunction
函数,用于在UObject
或者AActor
中查找某个函数名的函数并且返回其函数指针。
使用方法如下:
UFunction *Injured = this->FindFunction(TEXT("Injured"));
使用ProcessEvent
函数来进行函数的触发
在UE4中提供了ProcessEvent函数来进行触发函数指针对应的函数,具体使用方法如下:
UFunction *Injured = this->FindFunction(TEXT("Injured"));
if (Injured)
{
ProcessEvent(Injured, nullptr);
}
- ProcessEvent函数第一个参数是函数指针,第二个参数指的是参数列表,其类型为
void*
类型。
15、C++调用蓝图函数:BlueprintImplementableEvent函数说明符用法
摘自:http://aigo.iteye.com/blog/2272292
16、UE4中的委托
分为单播和多播
一、单播:
1、使用如下定义
|
2、声明和实现回调函数,注意:一定要加UFUNCTION修饰函数声明,因为委托是参与UE的反射系统中的,即UE引擎要知道有这个函数,这在下面的例子中会看到,声明和实现如下:
UFUNCTION()
void IntFunction(int32 Value)
{
GLog->Log(ELogVerbosity::Warning, "IntFunction: " + FString::FromInt(Value));
}
3、在触发的时候进行绑定
MyIntDelegate IntDelegate;
IntDelegate.BindUFunction(this, FName("IntFunction"));
4、执行委托
IntDelegate.Execute(999);
二、多播,使用Broadcast触发,Broadcast就意味着广播,这也正是观察者(Observer)模式。
MyIntMulticastDelegate IntMulticastDelegate;
IntMulticastDelegate.AddUFunction(this, FName("IntFunction"));
IntMulticastDelegate.AddUFunction(this, FName("SecondIntFunction"));
IntMulticastDelegate.AddUFunction(this, FName("ThirdIntFunction"));
IntMulticastDelegate.Broadcast(123);
17、在c++中的gamemode中通过ConstructorHelpers::FClassFinder查找并拿到一个类,并把DefaultPawn赋给它
18、在c++中PlayerController中有关输入的操作
首先在输入轴中设定好按键的绑定。
在PlayerController中有个SetUpInputComponent函数负责对输入的操作,调用InputComponent->BindAxis函数来绑定输入的事件名和回调函数,可以看到该函数第一个参数是输入事件名"MoveForward",第二个参数是哪个类调用的,就是该类this,第三个参数是传入回调函数AXPlayerController::MoveForward
19、在实现人物闪避的过程中,要产生闪避的位移,要么在动画里面root motion设置为enable,游戏中调用动画自动产生位移,要么把动画中的位移关了,在游戏逻辑中写一个给人物速度的位移逻辑,可以同一个launch character给人物一个方向的速度,只是最后再调用play montage函数播放对应的蒙太奇动画
20、给武器添加拖痕
再在人物骨骼创建两个socket,用于指定从哪两个Socket间播放特效
这动画里Notify添加一个trail。把两个节点拉开,也即在指定两动画帧中间播放,
在右侧属性中选择想要的粒子特效,粒子特效在First Socket Name到Second Socket Name间
18、
19、加上UPROPERTY()和不加有什么区别,大部分时候加上只是想使用虚幻提供的GC垃圾回收机制
20、Pawn、Controller和AnimInstance的相互调用
21、对于PlayerState类主要记录角色状态信息,在服务端为每个角色创建一个PlayerState,并把这个PlayerState复制到每个客户端上,它的生命周期和PlayerController一致
22、要取得一个类的类名,用类::StaticClass()还是指针->GetClass()?
最好用前一个,指针->GetClass在一些状况下有错
23、构造函数和Begin play()的区别:
构造函数和Begin Play的区别在于,同样是初始化,但是构造函数是在对象生成的时候就进行的初始化,或者说在类被实例化(创建出新的实例或者对象)时会执行一次,而Begin Play则是在游戏开始时进行的初始化。也就是说构造函数要更加早于Begin Play事件,并且构造函数相比之下更加的灵活,而且甚至可以在游戏运行之前就进行初始化。
对于蓝图构造函数,当你将类拖放到场景中时,它就被实例化了,这时就会调用一次。而当你拖动物体,旋转物体,缩放物体甚至修改它的参数,对他进行编译时,都会调用这个蓝图构造函数。这样能够反复利用的原理让这个函数有了更广泛的应用空间。
24、C++实现动态加载:LoadClass<T>()和LoadObject<T>() 和C++静态加载ConstructorHelpers::FClassFinder()
但是需要注意两个问题:
1、路径名也必须带_C后缀,2、把路径前缀BluePrint去掉
UClass* Test = LoadClass<AActor>(NULL, TEXT("/Game/Blueprints/MapPathBrush_BP.MapPathBrush_BP_C"));
25、把一个组件绑到另一个组件上
26、TSubclassOf的使用
摘自:https://blog.csdn.net/sukhoi27smk/article/details/78989656
27、在界面的控件和c++变量进行绑定的两种方式:
1、在界面的c++的.h中先创建变量
UPROPERTY()
UTextBlock* LoadingText;
然后在界面的c++的.cpp中的init方法中将界面里的控件和.h的变量绑定,这里TextBlock_Load是蓝图界面里控件的名字
2、
也即
要和界面中的按钮名字一致,这样也可以进行控件的绑定
28、
29、在游戏界面中除了绑定控件后还要调用initWidgetEvent函数用于处理按钮的点击事件响应,创建一个AttackBtnOnClickedEvent函数,通过函数回调将按钮点击事件绑定到该函数上。
30、character和PlayerController和PlayerState是如何进行数据传递的?
1、在Character中设置人物的血量HP,MP等数据
2、在PlayerController中拿到PlayerState(PlayerController中通过this->PlayerState方法就可以拿到玩家状态类)
3、初始化玩家状态,将从character传入的数据赋值给PlayerState
31、ue4-Network相关-变量同步
https://blog.csdn.net/yangxuan0261/article/details/54766951
ue4-Network相关-rpc调用
https://blog.csdn.net/yangxuan0261/article/details/54766955
ue4-Network相关-Client和Server的区分