UE C++基础
- 虚幻C++各个头文件的含义
- 虚幻 C++各个宏的作用
- 虚幻C++游戏架构,创建C++默认类
- 虚幻C++重写Beginplay、Tick、Endplay函数
- 虚幻C++UE_LOG和AddOnScreenDebugMessage
- 虚幻C++的基础变量类型
- 虚幻C++FString、FName、FText三者的区别和相互转化
- 虚幻C++容器
- 虚幻C++基础数据类型输出打印
- 虚幻C++的宏及其属性说明符和元数据说明符
- 虚幻C++Ubject的实例化
- 虚幻C++ UGameInstance的实例化
- 虚幻C++创建Actor添加初始化组件
- 虚幻C++创建摄像机摇臂和相机,并且设置旋转位移缩放
- 虚幻C++按键映射绑定以及使用鼠标滑轮控制镜头缩放远近
- 虚幻C++AddActorLocalOffset和AddActorWorldOffset
- 虚幻C++的代理绑定
- 虚幻C++碰撞设置
- 虚幻C++粒子特效的激活和失效
- 虚幻C++创建UserWidget并且绑定Button点击事件
- 虚幻C++进度条Progress的实现
- 虚幻C++的代理
- 虚幻C++子弹类型设置
- 虚幻C++创建Character添加增强输入
- 虚幻C++创建Interface接口
- 虚幻C++创建TimeHandle定时器
- 虚幻C++创建3DWidget并渲染到屏幕上
- 虚幻C++创建Apply Damage并且接受伤害TakeDamage
- 虚幻C++创建Timeline时间轴
- 虚幻C++射线检测LinetranceByChannel和LineTanceByObject
- 虚幻C++软引用
- 虚幻C++同步和异步加载资源
- 虚幻C++智能指针
- UE查找Actor的方式
虚幻C++各个头文件的含义
#pragma once
// 预处理程序指令 作用:保护同一个文件不会多次包含,
#include "CoreMinimal.h"
// 包含了一套来自UE4的核心变成环境的普遍存在类型
#include "GameFramework/GameModeBase.h"
// 包含了默认GameModeBase的头文件
#include "UEStudyGameModeBase.generated.h"
// 存储反射信息数据
虚幻 C++各个宏的作用
GENERATED_BODY()
//表示我们不使用父类的构造函数,如果我们要在我们自定义的类中做一些初始化操作,需要我们自己在.h头文件中
// 声明构造函数,然后在.cpp文件中实现该构造函数,它之后的成员的是private
GENERATED_UCLASS_BODY()//表示我们使用父类的构造,如果我们在自定义类中做一些初始化操作,可以直接在.cpp文件
// 中实现构造函数,而不需要在.h文件中去声明,这个宏会自动生成带有特定参数的构造函数,它之后的成员是public
UCLASS()//告知虚幻引擎生成类的反射数据,类必须派生自UObject
UPROPERTY()//叫做属性声明宏,虚幻C++在标准C++基础之上实现了一套反射系统(Reflection System)
// 反射系统负责垃圾回收、引用更新、编辑器集成等一系列高级且有用的功能,而UPROPERTY的作用就是
// 声明该属性在反射系统的行为
UFUNCTION()//函数声明宏,反射系统可识别的C++函数
USTRUCT()//结构体声明宏,反射系统可识别的C++结构体
UENUM()//枚举声明宏,反射系统可识别的C++枚举
虚幻C++游戏架构,创建C++默认类
世界场景设置
虚幻游戏架构组成:
- 游戏模式(GameMode):即游戏的技术规则,可包含出现的玩家和观众数量,以及允许的玩家和观众的最大数量,以及游戏是否暂停以及如何处理游戏暂停,玩家进入关卡的方式,关卡之间的过渡等
- 默认pawn类(Default Pawn Class):默认玩家角色类,可以是带有运动属性的character,也可以是不带有运动属性的pawn,相当于人体躯干,可以被controller控制,这个controller可以是玩家,也可以是aiController
- HUD类(HUD Class):用户界面类,绘制到屏幕上的UI,用来进行一些UI交互界面的展示
- 玩家控制器类(Player Controller Class):控制器是一个非物理的actor,可以拥有一个pawn或者是pawn的派生类,比如说charactor来控制其运动,可以是aiController,也可以是playerController,可以控制角色的移动,相当于给角色赋予了灵魂
- 游戏状态类(Game State Class):主要是追踪记录游戏层面的属性,比如说已经链接玩家的链表,团队的得分,开放世界中完成的任务等等
- 玩家状态类(Player State Class):追踪游戏玩家的状态属性,比如当前玩家的姓名、得分、在线状态等等
- 旁观者类(Spectator Class):第三方视角
创建C++默认类:
-
在UE中添加以上各个类
在VS中选择全部重新加载,会发现VS中多了private和public文件夹以及我们创建的类对应的.h和.cpp文件 -
在MyGameMode.h文件中添加加载我们创建的头文件,并创建一个默认构造函数
-
在MyGameMode.cpp文件中实现默认构造函数,并创建对应的C++默认类
-
关闭UE,生成并运行对应项目
-
在UE的世界场景设置中,将GameMode设置为我们创建的GameMode,即可完成游戏模式默认类创建
虚幻C++重写Beginplay、Tick、Endplay函数
-
在GameMode.h添加对应的构造函数,因为是重写的函数,所以需要关键字override,且Tick和EndPlay函数具有自带的参数
-
在GameMode.cpp中实现对应的构造函数,因为是继承自父类的函数,所以需要通过super关键字添加父类的对应函数
虚幻C++UE_LOG和AddOnScreenDebugMessage
输出日志UE_LOG
UE中应用此GameMode后运行的输出结果,在输出日志中
打印在屏幕上AddOnScreenDebugMessage
UE中应用此GameMode后运行的输出结果,在屏幕中
此打印相当于蓝图中的print string:
虚幻C++的基础变量类型
//布尔类型的变量声明
bool varBool;
//整形32位的变量声明
int32 varInt32;
//整形64位的变量声明
int64 varInt64;
// 字节类型的变量声明
BYTE varByte;
// 字符串类型的变量声明
FString varString;
// 名称类型的变量声明
FName varName;
// 文本类型的变量声明
FText varText;
// 向量类型的变量声明
FVector varVector;// 包含x轴、y轴、z轴的左边
//旋转向量类型的变量声明
FRotator varRotator;// 包含X轴的旋转Roll,y轴的旋转Pit,Z轴的旋转Yaw
// FTransform类型的变量声明
FTransform varTransform;// 包含FVector和FRotator以及缩放Scale三者的集合
虚幻C++FString、FName、FText三者的区别和相互转化
FString:提供了大量的字符串操作接口,三者之中唯一可以修改的字符串类型,消耗更高,性能更低
FName:更着重于表示名称,不区分大小写,不可以更改。引擎中的资源名称都是此类型。通过一个轻型的、系统重复使用的字符串,在创建时会根据内容创建一个哈希值,并且同样的内容指挥存储一次,通过哈希值进行FName的查找和访问的时候,速度比较快,也不需要比较字符串的内容,直接比较哈希值来区分不同FName的字符串
FText:着重于显示和本地化,显示可理解为玩家能直接看到的信息,本地化就是多种语言的处理,不可以更改,相较于另外,FText会更加臃肿,但是提供了非常优秀的本地化功能
//创建一个FString
FString myString = TEXT("I am String");
// FString转化为FName
FName myName = FName(*myString);
// FString转化为FText
FText myText = FText::FromString(myString);
// FName转化为FString
myString = myName.ToString();
// FName转化为FText
FText text1 = FText::FromName(myName);
// FText转化为FString
FString strFromText = text1.ToString();
// FText不能直接转化为FName,需要通过FString间接转化
虚幻C++容器
TArray
TArray:是虚幻C++中的动态数组TArray,索引值从0开始
特点:速度快,内存消耗小,安全性高,并且TArray所有元素均完全为相同类型,不能进行不同元素类型的混合
- 声明TArray变量以及打印函数
//声明一个整型32为的TArray
TArray<int32>myArray;
void PrintArray();
- 打印函数的实现:
void AMyGameMode::PrintArray()
{
// 用迭代器遍历、打印数组
for (auto It = myArray.CreateConstIterator(); It; It++)
{
UE_LOG(LogTemp, Warning, TEXT("%d"), *It);
GEngine->AddOnScreenDebugMessage(-1, 5.0, FColor::Blue, FString::Printf(TEXT("%d"), *It));
}
}
- 对TArray进行操作:增及其输出
//数组TArray中的操作
//增,将元素添加到数组当中
myArray.Add(10);
myArray.Add(20);
myArray.AddUnique(20);//如果数组中没有相同的元素,则将此数加入数组之中
myArray.Add(30);
myArray.AddUnique(40);
PrintArray();
- 对TArray进行操作:删改查
// 删,将元素从数组中删除
myArray.Remove(20);// 移除数组中所有等值的元素
myArray.RemoveAt(0);// 移除数组中索引值为0的元素
myArray.RemoveSingle(10);// 移除首个匹配到的元素,即移除碰到的第一个10
myArray.Empty();// 清空数组,数组内容数number为0
myArray.Reset();// 重置数组,将数组中的所有元素变为0,数量number不变
// 改
myArray.Insert(60, 0);// 在索引值为0的位置插入值60
int32& temp = myArray[0];
temp = 50;// 修改索引值为0的位置的数值为50
// 查
myArray.Contains(10);// 查找数组中是否包含某个元素,返回值为bool类型
myArray.Find(10);// 正向查找我们的第一个匹配的元素,找到则返回下标,否则返回-1
myArray.FindLast(10);// 反向查找我们匹配的第一个元素,找到则返回下标,否则返回-1
TMap
TMap:一种键值对容器,里面的数据都是成对出现的(key,value),value通过key值来获取,且key值不能重复,key值唯一
- 声明TMap变量及打印函数:
// 创建一个int32位的TMap类型变量
TMap<int32, int32>myMap;
void PrintMap();
- 打印函数的实现:
void AMyGameMode::PrintMap()
{
for (auto& TestMap : myMap)
{
GEngine->AddOnScreenDebugMessage(-1, 5.0, FColor::Blue, FString::Printf(TEXT("Key:%d Value:%d"), TestMap.Key, TestMap.Value));
UE_LOG(LogTemp, Warning, TEXT("Key:%d Value:%d"), TestMap.Key, TestMap.Value);
}
}
- TMap的相关操作:
// 增
myMap.Emplace(0, 1);// 用法同Array的add,往容器中添加数值
myMap.Emplace(1, 2);
myMap.Emplace(2, 3);
PrintMap();
// 删
myMap.Remove(0);// 移除key值为0的元素
myMap.Empty();// 清空Map中的数据
// 查
myMap.Contains(1);// 查找匹配的key值是否存在,找到返回真,否则为假,进行两次查找
int32* isFind = myMap.Find(6);// 查找匹配的key值是否存在,找到为真,否则为假,只进行一次查找,返回的是指针
const int32* isFind2 = myMap.FindKey(2);//反向查找,通过查找value的值来查找它对应的key,返回类型为指针
// 分别获取所有的keys和values
TArray<int32> testKeys;
TArray<int32> testValues;
myMap.GenerateKeyArray(testKeys);
myMap.GenerateValueArray(testValues);
TSet
TSet简介:
- 是一种快速容器,(通常)用于在排序不重要的情况下存储唯一元素
- TSet类似于TMap和TMultiMap,但有一个重要区别,TSet是通过对元素求值的可覆盖函数,使用数据本身作为键,而不是将数据值与独立的键相关联
- TSet可以非常快速地添加、查找和删除元素(恒定时间),-TSet也是值类型,支持常规复制、赋值和析构函数的操作,以及其元素较强的所有权
- 声明TSet变量及打印函数:
// 声明一个TSet类型的变量
TSet<FString>mySet;
void PrintSet();
- 打印函数的实现:
void AMyGameMode::PrintSet()
{
for (auto& testSet : mySet)
{
GEngine->AddOnScreenDebugMessage(-1, 5.0, FColor::Blue, FString::Printf(TEXT("%s"), *testSet));
UE_LOG(LogTemp, Warning, TEXT("%s"), *testSet);
}
}
- TMap的相关操作:
// TSet相关操作
// 增
mySet.Add(TEXT("Banana"));
mySet.Add(TEXT("Apple"));
mySet.Add(TEXT("Pineapple"));
mySet.Emplace(TEXT("orange"));//add和emplace都是添加元素到容器中,但是emplace可以避免在插入集合时创建的临时文件
PrintSet();
// 合并元素
TSet<FString>mySet2;
mySet2.Add(TEXT("zhangsan"));
mySet2.Add(TEXT("lisi"));
mySet2.Add(TEXT("wangwu"));
mySet.Append(mySet2);//将mySet2的值合并到mySet中
PrintSet();
// 移除元素
mySet.Remove(TEXT("Banana"));// 移除匹配的值,会返回已删除元素的数量,如果给定的键未包含在集合中,则返回0
mySet.Empty();// 清空容器,释放内存
mySet.Reset();// 清空集合元素,保留内存
// 查找元素
int32 Count = mySet.Num();// 查询集合中保存的元素数量,返回值为整型
bool isFind = mySet.Contains(TEXT("Banana"));// 查询是否包含特点元素,有则返回真,否则为假
FString* isFind2 = mySet.Find(TEXT("Banana"));// 查找是否包含特定元素,返回指向元素数组的指针,如果映射不包含该键,则返回为Null
// array函数
TArray<FString> fruitArray = mySet.Array();//函数会返回一个TArray,其中填充了TSet中每个元素的副本
// 排序
TSet<FString>testSet = { TEXT("a"),TEXT("aa"),TEXT("aaa"),TEXT("aaaa") };
testSet.Sort([](FString A, FString B) {return A.Len() > B.Len(); });// 按长度从长到短排列
// 赋值运算符 =
TSet<FString>newSet;
newSet = mySet;// 把mySet的值赋值给newSet
newSet.Add(TEXT("OneOne"));
// []运算符
FSetElementId index = newSet.Add(TEXT("TwoTwo"));// 根据FSetElementId访问集合对应元素的引用
testSet[index] = TEXT("One");
// Reserve 预先分配内存
TSet<FString>newSet1;
newSet1.Reserve(10);// 预先分配内存,若输入的Number大于元素个数,则会产生闲置内存(Slack)
// Shrink 从容器末端移除所有的Slack(闲置内存)
for (int32 i = 0; i < 10; i++)
{
newSet1.Add(FString::Printf(TEXT("newSet%d"), i));// 添加元素
}
for (int32 i = 0; i < 10; i += 2)
{
newSet1.Remove(FSetElementId::FromInteger(i));// 删除当前索引值下面的元素 删除元素产生限制内存
}
newSet1.Shrink();// 删除末端的空元素
// Compact 将容器中的所有空白元素集合到一起放到末尾,方便一起删除
newSet1.Compact();// 注意,Compact可能会改变元素之间的顺序,如果不想改变的话,可以使用CompactStable
newSet1.Shrink();
虚幻C++基础数据类型输出打印
// 基础数据类型的输出打印
int32 myInt = 10;
float myFloat = 5.0f;
bool myBool = true;
char myChar = 'a';
FString myString1 = TEXT("myString1");
FVector myVector = FVector(0, 0, 0);
UE_LOG(LogTemp, Warning, TEXT("%d"), myInt);
UE_LOG(LogTemp, Warning, TEXT("%f"), myFloat);
UE_LOG(LogTemp, Warning, TEXT("%d"), myBool);
UE_LOG(LogTemp, Warning, TEXT("%c"), myChar);
UE_LOG(LogTemp, Warning, TEXT("%s"), *myString1);
UE_LOG(LogTemp, Warning, TEXT("%s"), *myVector.ToString());
虚幻C++的宏及其属性说明符和元数据说明符
UPROPERTY宏,属性说明符和元数据说明符
UPROPERTY:通过反射把属性暴露在蓝图或者实例的细节面板中,从而实现C++和蓝图之间的通信或交互。虚幻会生成PROPERTY的反射数据,利用这些反射数据,我们在蓝图中可以找到这些变量或者方法
定义宏:(定义在MyPawn.h中)
// 仅在类默认设置中可见
UPROPERTY(VisibleDefaultsOnly)
int32 visibleDefaultsOnlyInt;
// 仅在实例化细节面板可见
UPROPERTY(VisibleInstanceOnly)
FString visibleInstanceOnlyString;
// 类默认设置和实例化细节面板中都可以见到
UPROPERTY(VisibleAnywhere)
FVector visibleAnywhereVector;
// 仅在类默认设置中可以编辑
UPROPERTY(EditDefaultsOnly)
int32 editDefaultsOnlyInt;
// 仅在实例化细节面板可以编辑
UPROPERTY(EditInstanceOnly)
FString editInstanceOnlyString;
// 类默认设置和实例化细节面板中都可以编辑
UPROPERTY(EditAnywhere)
FVector editAnywhereVector;
// 仅在蓝图中可读
UPROPERTY(EditAnywhere, BlueprintReadOnly)
int32 blueprintReadOnlyInt;
// 在蓝图中可读可写即可以获取和设置变量
UPROPERTY(EditAnywhere, BlueprintReadWrite)
int32 blueprintReadWriteInt;
// category目录
UPROPERTY(EditAnyWhere, BlueprintReadWrite, Category = "myIntValue")
int32 value1;
// category子目录
UPROPERTY(EditAnyWhere, BlueprintReadWrite, Category = "myIntValue|mySubIntValue")
int32 value2;
// meta元数据说明符
// DisPlayName别名
UPROPERTY(EditAnywhere, BlueprintReadWrite, meta = (DisPlayName = "myValue3DisPlayName"))
int32 myValue3;
// EditCondition 条件控制编辑 用一个变量控制另一个变量受否可以被编辑
UPROPERTY(EditAnywhere, BlueprintReadWrite, meta = (DisPlayName = "Controller"))
bool isController;
UPROPERTY(EditAnywhere, BlueprintReadWrite, meta = (EditCondition = "isController"))
float value3;
//Tooltip 解释说明我们的变量
UPROPERTY(EditAnywhere, BlueprintReadWrite, meta = (Tooltip = "isControllerTrue"))
bool isTrue;
// 蓝图生成时暴露
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "myExposeOnSpawn", meta = (ExposeOnSpawn = "ExposeOnSpawnValue"))
float myHealth;
定义完成后编译运行,在UE中创建基于MyPawn的蓝图类
命名为BP_MyPawn,位置存放在content中
蓝图的类默认设置面板:可以看到visibleDefaultsOnlyInt和visibleAnywhereVector,可以编辑EditDefaultsOnlyInt和editAnywhereVector
将类拖拽到场景中,即将类实例化,实例化细节面板:可以看到visibleInstanceOnlyString和visibleAnywhereVector,可以编辑editInstanceOnlyString和editAnywhereVector
在蓝图中搜索blueprintRead:其中:blueprintReadOnlyInt只能get,而blueprintReadWriteInt既可以get也可以set
在蓝图中搜索value:myIntValue目录下有一个mySubIntValue目录
在蓝图中搜索myValue3,发现没有,它被别名myValue3DisPlayName所替代了
蓝图的类默认值面板中,只有勾选Controller,才可以编辑Value3
蓝图中将鼠标放置在isTrue上即可查看对应的解释
打开关卡蓝图,搜索SpawnActor from class,class选择BP_MyPawn,即可看到效果
打开BP_MyPawn蓝图,新建变量,勾选生成时公开,即可使用蓝图达到同样的效果
UFUNCTION宏,属性说明符和元数据说明符
UFUNCTION宏:生成函数的一些反射数据,能够将一些函数暴露给蓝图,实现函数和蓝图之间的通信
定义宏:(定义在MyPawn.h中)
// 暴露PrintF1函数在蓝图中,能够在蓝图中进行调用
UFUNCTION(BlueprintCallable, Category = "myFunction")
void PrintF1();
// 纯虚函数的定义BlueprintPure
UFUNCTION(BlueprintCallable, BlueprintPure, Category = "myFunction")
bool PrintF2();
// BlueprintImplementableEvent在C++中声明,不能定义,蓝图可重载
// 无返回值的是事件,有返回值的是函数
UFUNCTION(BlueprintImplementableEvent)
void Test1();
UFUNCTION(BlueprintImplementableEvent)
int Test2();
UFUNCTION(BlueprintImplementableEvent)
void Test11(const FString &myString);
UFUNCTION(BlueprintImplementableEvent)
int Test22(const FString &myString);
// BlueprintNativeEvent在C++中声明和实现,蓝图可选择性重载
UFUNCTION(BlueprintNativeEvent)
void TestA();
UFUNCTION(BlueprintNativeEvent)
int TestB();
UFUNCTION(BlueprintNativeEvent)
void TestC(const FString &myString);
UFUNCTION(BlueprintNativeEvent)
int TestD(const FString& myString);
// meta 元数据说明符
UFUNCTION(BlueprintCallable,Category="myFunction",meta=(DisPlayName="myPrintTest"))
void PrintTest();
纯虚函数:也可以叫 抽象函数 ,一般来说它只有函数名、参数和返回值类型 ,不需要函数体 。 这意味着它没有函数的实现,需要让派生类去实现。 C++中的纯虚函数,一般在函数签名后使用=0作为此类函数的标志。
在MyPawn.cpp文件中实现两个printf函数的定义后,运行程序,在蓝图中搜索PrintF,发现显示的两个函数的图标颜色不同,绿色为纯虚函数
在蓝图中重载4个函数,蓝图中显示为:无返回值的是事件,有返回值的是函数
在MyPawn.cpp文件中实现四个TestABCD函数的定义(注意函数名称后要加上_Implementation,否则编译会报错)后,在蓝图中重载,蓝图中显示为:无返回值的是事件,有返回值的是函数
函数的使用:MyPawn.cpp文件
void AMyPawn::BeginPlay()
{
Super::BeginPlay();
TestA();
}
...
void AMyPawn::TestA_Implementation()
{
GEngine->AddOnScreenDebugMessage(-1, 5.0f, FColor::Red, TEXT("TestA"));
}
编译运行后,在蓝图中重载TestA函数,并添加输出为TestAHello
将蓝图拖拽到场景中,运行,发现TestAHello和TestA都会打印在屏幕中,即在C++实现的(本地实现)和在蓝图中重载的函数都会运行
在MyPawn.cpp中实现PrintTest函数后,运行项目,在蓝图中输入PrintTest,会发现没有,被myPrintTest替代了
UENUM(枚举)宏
UENUM(枚举)宏:生成枚举的反射数据,通过反射,将枚举暴露给蓝图,进行C++和蓝图之间的通信
定义声明方法一:(MyPawn.h文件中)
#pragma once
#include "CoreMinimal.h"
#include "GameFramework/Pawn.h"
#include "MyPawn.generated.h"
// BlueprintType:将枚举类型可以用于蓝图中的变量 蓝图中可以选择生成的变量类型为MyNumType
UENUM(BlueprintType)
namespace MyNumType
{
enum MyCustomEnum
{
Type1,
Type2,
Type3,
};
}
UCLASS()
class UESTUDY_API AMyPawn : public APawn
{
GENERATED_BODY()
public:
// Sets default values for this pawn's properties
AMyPawn();
protected:
// Called when the game starts or when spawned
virtual void BeginPlay() override;
public:
// Called every frame
virtual void Tick(float DeltaTime) override;
// Called to bind functionality to input
virtual void SetupPlayerInputComponent(class UInputComponent* PlayerInputComponent) override;
// 声明一个枚举变量
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "MyEnum")
TEnumAsByte<MyNumType::MyCustomEnum> MyCustomEnum;
};
编译运行后,在UE蓝图的细节面板中可以看到
定义声明方法二:(MyPawn.h文件中)
#pragma once
#include "CoreMinimal.h"
#include "GameFramework/Pawn.h"
#include "MyPawn.generated.h"
// 枚举声明方法二
UENUM(BlueprintType)
enum class EMyTestEnum :uint8
{
OneType UMETA(DisPlayName="OneType"),
TwoType UMETA(DisPlayName = "TwoType"),
ThreeType UMETA(DisPlayName = "ThreeType")
};
UCLASS()
class UESTUDY_API AMyPawn : public APawn
{
GENERATED_BODY()
public:
// Sets default values for this pawn's properties
AMyPawn();
protected:
// Called when the game starts or when spawned
virtual void BeginPlay() override;
public:
// Called every frame
virtual void Tick(float DeltaTime) override;
// Called to bind functionality to input
virtual void SetupPlayerInputComponent(class UInputComponent* PlayerInputComponent) override;
// 声明一个枚举变量
// 方法二对应
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "MyEnum")
EMyTestEnum MyCustonEnum2;
};
USTRUCT结构体宏
## USTRUCT结构体宏:生成结构体的反射数据,通过反射,将结构体里的变量或者方法暴露给蓝图
定义声明:(MyPawn.h文件中):
#pragma once
#include "CoreMinimal.h"
#include "GameFramework/Pawn.h"
#include "MyPawn.generated.h"
// BlueprintType让结构体可以在蓝图中创建变量,并且进入到变量中,可以将变量设置为结构体
// BlueprintType让蓝图中可以选择生成的变量类型为FMyTestStruct
USTRUCT(BlueprintType)
struct FMyTestStruct
{
GENERATED_USTRUCT_BODY()
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "myTestStruct")
int32 Healthl;
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "myTestStruct")
FString MyName;
};
UCLASS()
class UESTUDY_API AMyPawn : public APawn
{
GENERATED_BODY()
public:
// Sets default values for this pawn's properties
AMyPawn();
protected:
// Called when the game starts or when spawned
virtual void BeginPlay() override;
public:
// Called every frame
virtual void Tick(float DeltaTime) override;
// Called to bind functionality to input
virtual void SetupPlayerInputComponent(class UInputComponent* PlayerInputComponent) override;
// 声明一个结构体变量
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "myCustomStruct")
FMyTestStruct MyCustomStruct;
};
编译运行后,在蓝图中可以看到
将结构体用于table中:
- 添加C++类Object
- 在VS中选择全部重新加载,并在MyObject.h中声明结构体
#pragma once
#include "CoreMinimal.h"
// 数据表格类对应的头文件
#include "Engine/Classes/Engine/DataTable.h"
#include "UObject/NoExportTypes.h"
#include "MyObject.generated.h"
USTRUCT(BlueprintType)
// :public FTableRowBase:让结构体可以使用数据表格,所以需要继承此类
struct FMyDateTableStruct: public FTableRowBase
{
GENERATED_USTRUCT_BODY()
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "MyTestDataTableStruct")
float Health;
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "MyTestDataTableStruct")
FString Name;
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "MyTestDataTableStruct")
int32 Level;
};
UCLASS()
class UESTUDY_API UMyObject : public UObject
{
GENERATED_BODY()
};
编译成功后创建数据表格
将数据表格另存为csv格式,并导入ue项目:,选择MyDateTableStruct
虚幻C++Ubject的实例化
- 前面步骤中已经新建了MyIObject,所以直接在MyPawn.h中添加头文件和声明
#pragma once
#include "CoreMinimal.h"
#include "MyObject.h"
#include "GameFramework/Pawn.h"
#include "MyPawn.generated.h"
UCLASS()
class UESTUDY_API AMyPawn : public APawn
{
GENERATED_BODY()
public:
// Sets default values for this pawn's properties
AMyPawn();
protected:
// Called when the game starts or when spawned
virtual void BeginPlay() override;
public:
// Called every frame
virtual void Tick(float DeltaTime) override;
// Called to bind functionality to input
virtual void SetupPlayerInputComponent(class UInputComponent* PlayerInputComponent) override;
// 声明Object变量
UPROPERTY()
UMyObject* myTestObject;
};
- 在MyPawn.cpp中实现
#include "MyPawn.h"
// Sets default values
AMyPawn::AMyPawn()
{
// Set this pawn to call Tick() every frame. You can turn this off to improve performance if you don't need it.
PrimaryActorTick.bCanEverTick = true;
}
// Called when the game starts or when spawned
void AMyPawn::BeginPlay()
{
Super::BeginPlay();
//TestA();
// Object实例化的实现
TSubclassOf<UMyObject> MySubClassObject = UMyObject::StaticClass();
myTestObject = NewObject<UMyObject>(GetWorld(), MySubClassObject);
if (myTestObject)
{
UE_LOG(LogTemp, Warning, TEXT("myTestObject is %s"), *myTestObject->GetName());
}
}
- 编译运行后,打开UE,运行,有输出object的名称,即Object被实例化成功
获得Object的参数
- 为Object添加一个参数,并添加一个构造函数用于初始化:(MyObject.h中)
USTRUCT(BlueprintType)
// :public FTableRowBase:让结构体可以使用数据表格,所以需要继承此类
struct FMyDataTableStruct: public FTableRowBase
{
GENERATED_USTRUCT_BODY()
// 构造函数
FMyDataTableStruct();
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "MyTestDataTableStruct")
float Health;
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "MyTestDataTableStruct")
FString Name;
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "MyTestDataTableStruct")
};
UCLASS()
class UESTUDY_API UMyObject : public UObject
{
GENERATED_BODY()
public:
// 声明一个结构体变量
UPROPERTY()
FMyDataTableStruct myDataTableStruct;
};
MyObject.cpp,初始化:
#include "MyObject.h"
FMyDataTableStruct::FMyDataTableStruct()
{
// 初始化
Health = 10;
Name = TEXT("zhangsan");
Level = 1;
}
- 在MyPawn.cpp中添加打印Object的参数:
void AMyPawn::BeginPlay()
{
Super::BeginPlay();
//TestA();
// Object实例化的实现
TSubclassOf<UMyObject> MySubClassObject = UMyObject::StaticClass();
myTestObject = NewObject<UMyObject>(GetWorld(), MySubClassObject);
if (myTestObject)
{
UE_LOG(LogTemp, Warning, TEXT("myTestObject is %s"), *myTestObject->GetName());
UE_LOG(LogTemp, Warning, TEXT("myHeal is %f"), myTestObject->myDataTableStruct.Health);
UE_LOG(LogTemp, Warning, TEXT("myName is %s"), *myTestObject->myDataTableStruct.Name);
UE_LOG(LogTemp, Warning, TEXT("myLevel is %d"), myTestObject->myDataTableStruct.Level);
}
}
- 编译运行,打开UE,选择MyGameMode,运行:
虚幻C++ UGameInstance的实例化
GameInstance:全局唯一单例,这个在引擎初始化的时候就已经生成,一直存在到引擎关闭
作用:
- 引擎初始化与关闭时执行的逻辑
- 为游戏保存全局数据:比如上一个关卡的信息需要在下一个关卡使用时,我们用GameInstance保存数据但是只是临时数据,游戏结束则小时,如果想要本地持久保存数据需要用SavaGame
在UE中创建GameInstance:
在VS中,在MyGameInstance.h文件中为实例添加参数和构造函数:
#pragma once
#include "CoreMinimal.h"
#include "Engine/GameInstance.h"
#include "MyGameInstance.generated.h"
UCLASS()
class UESTUDY_API UMyGameInstance : public UGameInstance
{
GENERATED_BODY()
public:
// 创建构造函数
UMyGameInstance();
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "MyInstance")
FString myAppID;
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "MyInstance")
FString myUserID;
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "MyInstance")
FString myName;
};
在MyGameInstance.cpp文件的构造函数实现中,为实例的参数进行初始化:
#include "MyGameInstance.h"
UMyGameInstance::UMyGameInstance()
{
// 初始化数据
myAppID = TEXT("123");
myUserID = TEXT("456");
myName = TEXT("wangwu");
}
在MyPawn.h中添加MyGameInstance.h头文件,并声明实例:
// 游戏实例的头文件
#include "MyGameInstance.h"
UCLASS()
class UESTUDY_API AMyPawn : public APawn
{
GENERATED_BODY()
public:
// Sets default values for this pawn's properties
AMyPawn();
protected:
// Called when the game starts or when spawned
virtual void BeginPlay() override;
public:
// Called every frame
virtual void Tick(float DeltaTime) override;
// Called to bind functionality to input
virtual void SetupPlayerInputComponent(class UInputComponent* PlayerInputComponent) override;
// 声明游戏实例
UPROPERTY()
UMyGameInstance* myInstance;
};
在MyPawn.cpp中添加MyGameInstance的实例化与输出:
void AMyPawn::BeginPlay()
{
Super::BeginPlay();
// 单例的使用
myInstance = Cast<UMyGameInstance>(GetWorld()->GetFirstPlayerController()->GetGameInstance());
if (myInstance)
{
UE_LOG(LogTemp, Warning, TEXT("myInstance is %s"), *myInstance->GetName());
UE_LOG(LogTemp, Warning, TEXT("myAppID is %s"), *myInstance->myAppID);
UE_LOG(LogTemp, Warning, TEXT("myUserID is %s"), *myInstance->myUserID);
UE_LOG(LogTemp, Warning, TEXT("myName is %s"), *myInstance->myName);
}
}
编译运行,打开UE,在编辑-项目设置-地图和模式中,将游戏实例切换为MyGameInstance:
点击运行,查看输出日志:
虚幻C++创建Actor添加初始化组件
Actor:从程序实现角度说,Actor是构成游戏世界的所有元素以及在此之上,运行游戏的规则以及逻辑的抽象实例
在UE中添加C++类Actor:
在MyActor.h中添加各组件的头文件,并添加参数:
#pragma once
#include "CoreMinimal.h"
// 场景组件头文件
#include "Components/SceneComponent.h"
// StaticMesh组件头文件
#include "Components/StaticMeshComponent.h"
// 碰撞组件头文件
#include "Components/BoxComponent.h"
// 粒子特效组件
#include "Particles/ParticleSystemComponent.h"
// 声音组件
#include "Components/AudioComponent.h"
#include "GameFramework/Actor.h"
#include "MyActor.generated.h"
UCLASS()
class UESTUDY_API AMyActor : public AActor
{
GENERATED_BODY()
public:
// Sets default values for this actor's properties
AMyActor();
protected:
// Called when the game starts or when spawned
virtual void BeginPlay() override;
public:
// Called every frame
virtual void Tick(float DeltaTime) override;
// 声明变量
UPROPERTY(VisibleAnywhere, BlueprintReadOnly, Category = "mySceneComponent")
class USceneComponent* MyScene;
UPROPERTY(VisibleAnywhere, BlueprintReadOnly, Category = "mySceneComponent")
class UStaticMeshComponent* MyMesh;
UPROPERTY(VisibleAnywhere, BlueprintReadOnly, Category = "mySceneComponent")
class UParticleSystemComponent* MyParticle;
UPROPERTY(VisibleAnywhere, BlueprintReadOnly, Category = "mySceneComponent")
class UBoxCompone