认识UE中的宏
UE类似于一个大型的Unity的编辑器,里面有很多内置的功能,本系列旨在记录UE的学习笔记,第一篇主要学习基础
类与结构体
UE的C++是修改过的C++,与C#类似,有GC垃圾回收,当然,前提是要这个类继承自UObject类(UE默认的对象类),与C#不同的是,继承自UObject类的子类,必须要用到指针来使用其中的函数(方法)与变量等
类的声明
一个普通UObject类,需要一个.h头文件和.cpp源文件,头文件中必须存在该类的.generated.h文件让虚幻编辑器识别并能正常生成对应的类
#pragma once
#include "TestClass.generated.h"
UCLASS()
class MYPROJECT_API UTestClass : public UObject
{
GENERATED_BODY()
public:
UTestClass();//构造函数
};
上面即为TestClass类的一个最基础的头文件,我们逐一进行讲解
- #pragma once即只编译一次,防止多次编译
- include “TestClass.generated.h”,包含了对应类的generated文件,系统会自动生成UClass,GENERATED_BODY(),以及类名等
- UClass,是一个宏,可以在其中标记为Blueprintable(蓝图化的),BlueprintType(蓝图类型)等,让UE将其在蓝图中可视化
- GENERATED_BODY(),UE自动生成的宏反射,用于让UClass等起作用
在头文件中,可以声明类所拥有的函数,变量等,与c#不同的是,C++直接用public或protected块,例如:
public :
void SayHello();
void Play();
private:
int32 Age;
FText Name;
头文件中只是为了定义,真正的函数实现则在.cpp文件中
#include "TestClass.h"//需要包含头文件
void UTestClass::SayHello()
{
UE_LOG(LogGameplayTags, Error, TEXT("你好"));
}
结构体与之类似,只是将UCLASS改为USTRUCT即可
其他的宏
除了类和结构体,还有一些其他的宏
宏属性
在任意一个类的字段中,加上UPROPERTY()定义
里面常用BlueprintReadWrite(蓝图可读写),BlueprintReadOnly(蓝图只读),EditAnywhere(随处可编辑),
Catagory=“”,等号后面的字符串用于给该字段分类。比如将血量和蓝量都划分到玩家属性的分类
meta=(),meta主要是为属性增加一些特殊的处理,比如括号中放MultiLine,可以让字符串(FText)多几行,这里不再赘述
宏函数
在任意一个类的字段中,加上UFUCTION()定义
里面常用BlueprintCallable(蓝图可调用),BlueprintPure(蓝图仅取值)等
当然方法中也能用Catagory与meta
宏标签
UE中的宏标签主要是为了替代分散的枚举值,转而进行系统化的标签,想要使用宏标签,需要在项目文件的Build.cs文件中的PublicDependencyModuleNames中添加"GameplayTags"就能使用。
在对应的TagSystem.h类中声明宏标签
#pragma once
#include "CoreMinimal.h"
#include "NativeGameplayTags.h"
UE_DECLARE_GAMEPLAY_TAG_EXTERN(TAG1)
UE_DECLARE_GAMEPLAY_TAG_EXTERN(TAG2)
UE_DECLARE_GAMEPLAY_TAG_EXTERN(TAG3)
UE_DECLARE_GAMEPLAY_TAG_EXTERN即为定义宏标签的定义,括号中的名称由你自行定义
有了定义自然会有声明,声明常常用字符串进行,如
#include "Item/ItemSystemTags.h"
UE_DEFINE_GAMEPLAY_TAG(TAG1,"Tag1")
UE_DEFINE_GAMEPLAY_TAG(TAG2_"Tag2")
UE_DEFINE_GAMEPLAY_TAG(TAG3,"Tag3")
任意位置使用时,只需要FGameplayTag MyTag=TAG1;
宏事件
宏事件的声明与宏标签类似
在需要事件的类中
DECLARE_DYNAMIC_MULTICAST_DELEGATE_ThreeParams(FOnEvent,int32,arg1,int32,arg2,int32,arg3);
上面声明了一个三个参数的事件,参数与参数名之间用逗号隔开,第一个参数是事件名,你也可以声明更多或者更少事件的参数,修改宏即可,使用时,就像正常的字段一样
UPROPERTY(BlueprintAssignable,Category="Events"),第一个为蓝图可触发
FOnEvent MyEvent;
MyEvent.Broadcast(1,2,3);//触发事件
注意,以上事件为多播委托
宏接口
想要声明蓝图接口,需要让对应接口类继承自UInterface类
#pragma once
#include "CoreMinimal.h"
#include "UObject/Interface.h"
#include "ConsumableItemInterface.generated.h"
// This class does not need to be modified.
UINTERFACE()
class UConsumableItemInterface : public UInterface
{
GENERATED_BODY()
};
class MYPROJECT_API IConsumableItemInterface//在I开头的这里声明要实现的函数
{
GENERATED_BODY()
// Add interface functions to this class. This is the class that will be inherited to implement this interface.
public:
UFUNCTION(BlueprintCallable,BlueprintNativeEvent)
bool ConsumeItem(AActor* TargetActor);
};
接口实现
#pragma once
#include "CoreMinimal.h"
#include "ItemInstance.h"
#include "Item/Interfaces/ConsumableItemInterface.h"
#include "ConsumableInstance.generated.h"
UCLASS()
class MYPROJECT_API UConsumableInstance : public UItemInstance,public IConsumableItemInterface
{
GENERATED_BODY()
public:
virtual bool ConsumeItem_Implementation(AActor* TargetActor) override;//这里要加上virtual,override
};
宏枚举
普通的UENUM即可,不再赘述
以上便是UEC++的常用宏,下面介绍一些常用知识点
引用头文件
在C#中,我们想要用到其他程序集中的类,可以使用命名空间namespace,而C++中,我们则要用到对应的头文件
以上一段代码块为例#include "Item/Interfaces/ConsumableItemInterface.h"只有包含了这个我们才能使用这个接口,才能得知它有哪些函数
如果我们仅仅只需要知道有这个类而不关心它的内部成员,可以直接用前向声明,将头文件改为 class IConsumableItemInterface,如果可以使用前向声明时,请尽量使用前向声明
前向声明可以用来解决头文件循环引用的问题(如类A引用B,类B引用A)
Tick
继承自AActor的对象,类似Unity中的GameObject,自然有BeginPlay(类似Start),Tick(类似Update)的方法,照常使用即可,这里性能优化的点是如果不需要用到Tick,请在构造函数中将PrimaryActorTick.bCanEverTick 设为false,能将该物体移出Tick队列从而节省性能
UPrimaryDataAsset
类似Unity中的ScriptableObject,可以将数据资产化,创建时只需在编辑器中找到DataAsset,再选中你写好的继承类,就可以直接使用了
结语
由于Unity的NGO入门过于简单而深入又过于困难,所以有了这篇文章,NGO的学习正在缓慢推进,所以提前开了虚幻的坑
1万+

被折叠的 条评论
为什么被折叠?



