UE4基础 文档:https://docs.unrealengine.com/4.27/en-US/
UE4项目目录结构 Binarires:存放编译生成结果的二进制文件
Config:存放当前项目的配置文件(中医)
Content:存放平常最常用到所有的资源和蓝图(重要)
Intermediate:中间文件(gitignore),存放一些临时生成的文件
Save:存储自动保存的文件,日志文件,引擎崩溃日志,硬件信息,烘焙信息数据等。
Source:C++源码文件(重要)
DerivedDataCache:渲染缓存,C盘不够的情况下,会将缓存文件存储在该目录下。
编译类型 编译类型分为两种:
Editor:编辑器型与UE4Editor配合编译便于制作开发
Game:游戏型可以直接从源代码运行游戏不关心编辑端
1 2 3 4 5 DebugGame:游戏调试(只适合游戏代码) DebugGame Editor:游戏调试时通过UE4Editor进行调试 Development:游戏开发型调试(适合查看源代码执行) Development Ediotr:游戏开发型调试在UE4Editor中进行(默认情况) Shipping:发现模式没有了调试辅助
编译系统 UE4支持全平台开发,为了方便开发者使用同一套代码在全平台下发布,所以UE4使用了自定义编译系统。他也可以保证开发者的代码包括在UE4Editor下的参数设定,可以全平台适用。
这套自定义编译系统是在VS编辑器后台通过命令行默默执行的,他最重要的两个工具是UBT和UHT。
UBT(Unreal Build Tools)
* ue4自定义的一种编译工具
* 他使用的是C#语言
* 用来逐步编译Engine的代码模块和项目的代码模块
* 对项目的C++代码来说主要用于处理项目对引擎功能模块的依赖
UHT(Unreal Header Tool)
* ue4 对项目C++代码的解析工具
* 它可以将项目的C++代码翻译成UE4 Editor认识的特殊编码
* 它主要是为了给UE4Editor提供C++代码的可视化功能
C++基础 foreach 1 2 3 4 int numbers[] = {1 , 2 , 3 , 4 , 5 };for (auto c : numbers) { cout << c << endl; }
智能指针 auto_ptr 1 2 3 4 5 6 7 8 9 void TestAutoPtr () { auto_ptr<Myclass> p (new Myclass) ; if (nullptr != p.get) { p.get ()->member = "aaa" ; p->Print (); } }
shared_ptr 1 2 3 4 5 6 7 8 shared_ptr<int> p1(new int(10)); shared_ptr<int> p1; p1 = make_shared<int>(10); // shared_ptr<int> p2(p1); //拷贝构造 // shared_ptr<int> p3(move(p1));// 移动构造 // p2.use_count(); // 返回使用次数
wake_ptr 1 2 3 4 5 6 7 8 wake_ptr<int> pw1; shared_ptr<int> ps1 = make_share<int>(1); pw1 = ps1; // 不会增加ps1的引用计数 // 注意:因为弱引用指针不会增加计数器,为了程序安全,不能作为返回值。一般用作形参。 // 在使用的时候需要锁住对象,避免对象释放掉了再使用。 if(ps1.expired()) { // 表示安全 *(ps1.lock().get()) = 10; // lock返回共享指针,并对里面的值进行赋值。 }
unique_ptr 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 ``` ### Lamda ```c++ #include<iostream> #include<functional> using namespace std; int main() { auto f = [](int a, int b) { return a + b; }; cout << f(1, 2) << endl; int a = 4; auto f2 = [=](int b) { // =代表值捕获当前作用域内的所有变量 return a + b; }; cout << f2(2) << endl; auto f3= [&](int b) { // &代表地址捕获当前作用域内的所有变量 return a + b; }; cout << f3(2) << endl; int c = 5; auto f4= [=, &c](int b) { // 值捕获全部变量,c进行地址捕获 return a + b + c; }; cout << f4(2) << endl; // 采用function来获取返回值调用 function<int(int, int)> f5 = [&](int a, int b)-> int { return a + b + c; }; cout << f5(1, 2) << endl; // 直接调用 cout << [=](int a, int b)-> int { return a + b + c; }(1, 2); }
UE4 C++ 基础 命名规则 虚幻引擎封装了许多自定义的数据类型:类、结构、枚举;
自定义了所有的数据结构:动态数组、链表、集合、图、各种字符串操作;
对自己的封装形式做了如下区分:
A字母开头:表示当前类对象来自于AActor
U字母开头:表示它一定继承于UObject
F字母开头:大量使用在结构体当中,也有很多类使用他开头,如果类使用F开头,表示当前类不会继承UObject;
I字母开头:表示当前对象是接口类型;// 继承了大量的纯虚函数,没有实现,需要自己实现。
E字母开头:表示当前类型是枚举;
T字母开头:表示模板类,一般用于数据结构定义,多线程安全类;
如果字母全部大写,那么表示宏定义出来的。
打印日志 虚幻引擎日志分为两类:
终端输出
屏幕输出
需要注意的是, 虚幻引擎本身采用的是UTF-16字符编码集,Windows采用的是Unicode,两个字符集不通用,只有ASCII码表可以交互,对中文输出是乱码。
终端输出 虚幻引擎将日志分为三类:
Message(描述一般信息)
Warrning(描述警告,一般为黄色)
Error(描述发送致命错误,红颜色)
向终端输出函数:
UE_LOG(日志分类, 日志种类, 字符串格式化, 字符串参数, …)
1 2 3 UE_LOG (LogTemp, Warning, TEXT ("开始" ));UE_LOG (LogTemp, Display, TEXT ("display" ));UE_LOG (LogTemp, Warning, TEXT ("The Actor's name is %s" ), TEXT ("Myactor" ));
自定义log类型:
头文件中声明
1 DECLARE_LOG_CATEGORY_CLASS (MyLog, Log, All);
cpp文件中实例
1 2 3 DEFINE_LOG_CATEGORY_CLASS(AMyActor, MyLog); // 使用 UE_LOG(MyLog, Display, TEXT("display"));
屏幕输出 1 void UEngine::AddOnScreenDebugMessage(int32 Key, float TimeToDisplay, FColor DisplayColor, const FString& DebugMessage, bool bNewerOnTop, const FVector2D& TextScale)
Key:缩进, -1自动计算
TimeToDisplay:显示多少秒
DisplayColor:打印颜色
DebugMessage:打印消息
bNewerOnTop:是不是从新的Top开始打印
TextScale:字体的缩小放大
1 2 GEngine->AddOnScreenDebugMessage (-1 , 5.0f , FColor::Red, TEXT ("InputComponent Enabled!" )); GEngine->AddOnScreenDebugMessage (-1 , 5.0f , FColor::Red, TEXT ("Test!" ), true , );
运行顺序 编译器运行: 构造函数,PostInitProperties
运行期运行:函数,PostInitProperties
AMyActor 在编译完成后调用和运行时调用
先执行构造函数:引擎编译成功时就会调用对象的构造函数。这时为了与蓝图挂钩。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 AMyActor::AMyActor () { PrimaryActorTick.bCanEverTick = true ; UE_LOG (LogTemp, Warning, TEXT ("构造" )); auto pSecen = CreateDefaultSubobject <USceneComponent>(FName (TEXT ("Root" ))); SetRootComponent (pSecen); APlayerController *pc = UGameplayStatics::GetPlayerController (GetWorld (), 0 ); EnableInput (0 ); if (nullptr != InputComponent) { GEngine->AddOnScreenDebugMessage (-1 , 3.0f , FColor::Red, TEXT ("InputComponent Enabled!" )); } }
绝对不要再里面写一些空指针内存错误,会导致Editor打不开。
PostInitProperties 在编译完成后调用和运行时调用,对Actor所有属性进行初始化,编辑器类属性
重写
1 virtual void PostInitProperties () override ;
1 2 3 4 void AMyActor::PostInitProperties () { Super::PostInitProperties (); }
PostInitializeComponents 在运行期调用,早于BeginPlay
1 2 3 4 5 void AMyActor::PostInitializeComponents() { Super::PostInitializeComponents(); }
BeginPlay 游戏启动时调用
1 2 3 4 5 // Called when the game starts or when spawned void AMyActor::BeginPlay() { Super::BeginPlay(); }
Tick 每一帧都调用,该函数的执行会取决于PrimaryActorTick.bCanEverTick
,一般在构造函数中会设置该值为true;
1 2 PrimaryActorTick.bCanEverTick = true ;
1 2 3 4 5 // Called every frame void AMyActor::Tick(float DeltaTime) { Super::Tick(DeltaTime); }
EndPlay 在结束运行的时候调用,释放对象的时候,在该函数中进行释放。
1 virtual void EndPlay(const EEndPlayReason::Type EndPlayReason) override;
1 2 3 4 5 6 7 void AMyActor::EndPlay(const EEndPlayReason::Type EndPlayReason) { // 一定要在调用Super::EndPlay(EndPlayReason);之前,先释放对象 Super::EndPlay(EndPlayReason); }
BeginDestroy 在结束运行的时候调用,在EndPlay之后调用。
1 virtual void EndPlay(const EEndPlayReason::Type EndPlayReason) override;
1 2 3 4 void AMyActor::EndPlay(const EEndPlayReason::Type EndPlayReason) { Super::EndPlay(EndPlayReason); }
设置类变量属性 1 2 UPROPERTY (EditAnywhere, BlueprintReadWrite, Category="FLValues" ) FString myText = TEXT ("Hello World!" );
字符串 虚幻采用UTF-16的编码格式,他使用的字符类型为TCHAR,向外打印输出一定采用TCHAR类型。
将Ascii码转tchar
1 TCHAR * chars = ANSI_TO_TCHAR("1234");
将TCHAR转char
1 ANSICHAR* ansic TCHAR_TO_ANSI(chars);
转为UTF-8
采用TEXT可直接将字符串转换为TCHAR类型。
UE4定义的字符串类解释
FName:用于描述资源名称或路径,对于组件或Actor命名的时候用到它,只读属性。
FText:UE4本地化字符类型,用于描述不同操作系统下的统一字符类型,只读属性。
FString:标准TCHAR动态字符串。
FString 初始化
追加
1 2 3 a += TEXT (" " ); a.Append (TEXT ("!" )); a.InsertAt (2 , TEXT ("%" ));
判断字符串是否存在
1 2 3 4 5 6 if (a.Contains (TEXT ("%" ))) { }
查找字符串
1 2 3 4 5 6 7 8 9 10 11 int idx = a.Find (TEXT ("%" ), ESearchCase::CaseSensitive, ESearchDir::FromStart, 0 );if (idx >= 0 ) { }else { }
删除字符串
1 2 a.RemoveAt (0 , 1 , true );
判断是否为空
获取长度
将int转化为FString
1 2 FString s = FString::FormatAsNumber(1);
将FString转化为int
1 int n2 = FCString::Atoi(TEXT("123"));
将float类型转换为FString
1 FString::SanitizeFloat(2.0f);
将FString类型转换为float
1 float n = FCString::Atof(TEXT("1.2"));
格式化字符串
1 2 FString FString::Format (const TCHAR* InFormatString, const FStringFormatNamedArguments& InNamedArguments) ;FString FString::Format (const TCHAR* InFormatString, const FStringFormatOrderedArguments& InOrderedArguments) ;
例子
1 2 3 4 TArray<FStringFormatArg> args; args.Add (TEXT ("你好" )); args.Add (0 ); FString out = FString::Format (TEXT ("FString fomat str={0}, num={1} " ), args);
FName 在构造时进行赋值
1 FName name(TEXT("RootComponent"));
FString对FName进行赋值
1 2 name = *FString(TEXT("FString")); name = *FString(TEXT("/Game/MobileStarterContent/Maps/StarterMap.StarterMap"));
将FName转换为FString
1 FString out2 = name.ToString();
FText 在做UI编程的时候,FText比较常用。
1 2 3 FText text = FText::AsNumber (1.0f ); text = FText::FromString (FString (TEXT ("dddd" ))); FString fs = text.ToString ();
UE4 C++数据结构 TArray 初始化
1 2 TArray<int32> arr; arr.Init (2 , 10 );
添加元素
1 2 3 4 5 6 7 8 9 arr.Add (123 ); arr.Emplace (35 ); arr.Push (100 ); arr.Num (); arr.Remove (123 ); arr.RemoveAt (0 , 3 , true ); arr.Empty (); arr.RemoveAll ([](const int32 val) { return val > 2 ; });
采用foreach 循环
1 2 3 4 for (auto c : arr) { GEngine->AddOnScreenDebugMessage (-1 , 3.0f , FColor::Red, FString::FormatAsNumber (c), true , FVector2D (2.0f , 2.0f )); }
采用迭代器循环,利用迭代器效率最高。
1 2 3 4 5 6 7 8 9 10 auto pFunc = [](TArray<int32> arr)->void { if (arr.Num () > 0 ) { for (TArray<int32>::TConstIterator it = arr.CreateConstIterator (); it; ++it) { UE_LOG (MyLog, Display, TEXT ("Arr = %d" ), *it); } } };
组件 创建组件
1 2 USceneComponent *root = CreateDefaultSubobject<USceneComponent>(FName(TEXT("Root"))); SetRootComponent(root);
创建对象
UMG UMG:(Unreal Motion Graphics UI Designer)****虚幻示意图形界面设计器
是一个可视化的UI创作工具,可以用来创建UI元素,如游戏中的HUD、菜单或您希望呈现给用户的其他界面相关图形。UMG的核心是控件,这些控件是一系列预先制作的函数,可用于构建界面(如按钮、复选框、滑块、进度条等)。这些控件在专门的控件蓝图中编辑,该蓝图使用两个选项卡进行构造:设计器(Designer)选项卡允许界面和基本函数的可视化布局,而图表(Graph)选项卡提供所使用控件背后的功能。
ref:https://docs.unrealengine.com/4.27/zh-CN/InteractiveExperiences/UMG/
HUD:(Head Up Display)
安卓打包 ref: https://zhuanlan.zhihu.com/p/385138133
Edit->Project Settings->Packaging->Project->Build Configureation设置为Shipping (发行模式)。
常用API 获取第一个PlayerController
1 APlayerController* PlayerController = GetWorld ()->GetFirstPlayerController ();
获取鼠标屏幕上的位置
1 2 FVector2D MousePos = FVector2D (0 , 0 ); PlayerController->GetMousePosition (MousePos.X, MousePos.Y);
获取鼠标在世界里的位置
1 2 FVector MouseLocation, MouseDirection; PC->DeprojectMousePositionToWorld (MouseLocation, MouseDirection);
在一定范围内返回差值
1 float XDirection = FMath::Clamp( ObjLocation.X - MousePos.X, -1.0f, 1.0f);
实现对象在X轴上的移动
1 2 FVector Direction = FVector (XDirection, 0 , 0 );AddMovementInput (Direction);