UE4C++开发基础
UE4C++开发基础
前言
UE4有些代码块与方法容易遗忘或者有些块比较懒得写,此篇章用于记录常见的一些东西,便于自己查找拷贝使用,毕竟高端的程序员都是CV程序员,小编正在努力中(Ctrl+C Ctrl+V)
注:此篇章会随时增加,有些可能不完善
正文
日志
屏幕上的日志打印
#include "Engine.h"
GEngine->AddOnScreenDebugMessage(-1, 20, FColor::Red, FString(TEXT("GO!")));
#include "Kismet/KismetSystemLibrary.h"
UKismetSystemLibrary::PrintString(this, TEXT("Successed!"));
#include "Kismet/KismetSystemLibrary.h"
int num;
UKismetSystemLibrary::PrintString(this, TEXT("GOGOGO :%d"), num);
引用传递
UFUNCTION(BlueprintCallable, Category = "Tool Menus", meta = (ScriptMethod))
static void SetToolTip(UPARAM(ref) FToolMenuEntry& Target, const FText& ToolTip);
C++语法复习
mutable 所修饰的变量,可以在带const的函数里面去修改
普通日志(Output Logs)
UE_LOG宏输出Log,第一个参数为Log的分类(需要预先定义)。第二个参数为类型,有Log、Warning、Error三种类型。Log为灰色,Warning为黄色,Error为红色。TEXT内容可以根据需要自行构造。
UE_LOG(LogTemp, Warning, TEXT("GO GO %s"), *(FString("GO!")));
%s字符串(FString)
%d整型数据(int32)
%f浮点形(float)
任意参数日志
template <typename Type>
void Print(Type TValue)
{
FString TValueAsString;
if constexpr (std::is_integral_v<Type>)
{
TValueAsString = FString::Printf(TEXT("%d"), TValue);
}
else if constexpr (std::is_floating_point_v<Type>)
{
TValueAsString = FString::Printf(TEXT("%f"), TValue);
}
else if constexpr (std::is_same_v<Type, wchar_t*>)
{
TValueAsString = FString::Printf(TEXT("%s"), reinterpret_cast<wchar_t*>(TValue));
}
else if constexpr (std::is_same_v<Type, const wchar_t*>)
{
TValueAsString = FString::Printf(TEXT("%s"), reinterpret_cast<const wchar_t*>(TValue));
}
else if constexpr (std::is_same_v<Type, const char*>)
{
TValueAsString = FString(UTF8_TO_TCHAR(TValue));
}
else if constexpr (std::is_base_of<FString, Type>())
{
TValueAsString = FString::Printf(TEXT("%s"), *TValue);
}
else if constexpr (std::is_base_of<FName, Type>())
{
const FName Name = static_cast<FName>(TValue);
TValueAsString = FString::Printf(TEXT("%s"), *Name.ToString());
}
else if constexpr (std::is_base_of<FVector, Type>())
{
const FVector Vector = static_cast<FVector>(TValue);
TValueAsString = FString::Printf(TEXT("%s"), *Vector.ToString());
}
else if constexpr (std::is_base_of<FRotator, Type>())
{
const FRotator Rotator = static_cast<FRotator>(TValue);
TValueAsString = FString::Printf(TEXT("%s"), *Rotator.ToString());
}
else if constexpr (std::is_base_of<FTransform, Type>())
{
const FTransform Transform = static_cast<FTransform>(TValue);
TValueAsString = FString::Printf(TEXT("%s"), *Transform .ToString());
}
// ....解析自己需要打印的结构体
if (GEngine)
{
GEngine->AddOnScreenDebugMessage(-1, 10.f, FColor::Red, TValueAsString);
UE_LOG(LogTemp, Log, TEXT("%s"), *TValueAsString );
}
}
自定义LogCategory
在使用DEFINE_LOG_CATEGORY_STATIC
自定义Log分类的时候,我们可以将此宏放在你需要输出Log的源文件顶部。为了更方便地使用,可以将它放到PCH文件里,或者模块的头文件里(原则上是将Log分类定义放在被多数源文件include的文件里)。
DEFINE_LOG_CATEGORY_STATIC(LogMyCategory,Warning,All);
查看日志
Game模式
在Game(打包)模式下,记录Log需要在启动参数后加-Log。
编辑器模式
在编辑器下,需要打开Log窗口(Window->DeveloperTools->OutputLog)
字符串转换
FString from int
int a=10;
FString::FromInt(a)
FString to float
FString TestString = "121.56";
float myFloat = FCString::Atof(*TestString);
FString to FText
FString TestString = TEXT("str");
FText TestFText = FText::FromString(TestString );
FString to FName
FName TestFName = FName(FString("Text"));
FString to std::string
#include <string>
std::string TestString = "Text";
FString TextString(TestString.c_str())
std::string to FString
#include <string>
FString TestFString = "Text";
std::string myString (TCHAR_TO_UTF8(*TestFString));
FText to FString
FText TestFtext;
FString TestFString = TestFtext.ToString();
FString to const char*
*FString ()
const char* testChar = TCHAR_TO_ANSI(*FString("Text"));
值转std::to_string
std::string to_string( long value );
std::string to_string( long long value );
std::string to_string( unsigned value );
std::string to_string( unsigned long value );
std::string to_string( unsigned long long value );
std::string to_string( float value );
std::string to_string( double value );
std::string to_string( long double value );
生成与实例
如果你的类是一个纯C++类型(F开头),你可以通过new来产生对象。
如果你的类继承自UObject但不继承自Actor,你需要通过NewObject函数来产
生出对象。
如果你的类继承自AActor,你需要通过SpawnActor函数来产生出对象。
生成
NewObject<T>()
GetWorld()->SpawnActor<T>(UClass, FTransform);
创建相机:
UCameraComponent* Camera = CreateDefaultSubobject<UCameraComponent>(TEXT("Camera0"));
根据路径加载生成人物基础模型
USkeletalMesh* Sk_Mesh = Cast<USkeletalMesh>(StaticLoadObject(USkeletalMesh::StaticClass(),
NULL,
TEXT("/Game/Mannequin/Character/Mesh/SK_Mannequin"))
);
基于路径创建对应的动画实例
static ConstructorHelpers::FClassFinder<UAnimInstance> meshAnima(
TEXT("/Game/Mannequin/Animations/ThirdPerson_AnimBP")
);
查找与遍历
调用此方法需要给需要遍历的Actor设置好Tag
#include "Kismet/GameplayStatics.h"
TArray<AActor*> Actors;
UGameplayStatics::GetAllActorsWithTag(GetWorld(), TEXT("ActorTag"), Actors);
for (AActor* Actor: Actors)
{
}
获取所有的Actor
#include "Kismet/GameplayStatics.h"
TArray<AActor*> Actors;
UGameplayStatics::GetAllActorsOfClass(GetWorld(), AActor::StaticClass(), Actors);
for (AActor* Actor : Actors)
{
}
注:以上俩种方式只能用于Actor
对继承自Object的物体进行遍历,这种遍历方式会多出一倍,因为它会把所有引用的地方都遍历出来,而PIE运行时候是PIE的world里运行,这时候,你编辑器的world加PIE的world就是俩倍,如果只想要PIE的,就应该采用下方的方法
for (TObjectIterator<USkeletalMeshComponent> It; It; ++It)
{
USkeletalMeshComponent* SkelComp = *It;
if( SkelComp->GetScene() == InWorld->Scene )
{
SkelComp->bShowPrePhysBones = bShowPrePhysSkelBones;
SkelComp->MarkRenderStateDirty();
}
}
for (TActorIterator<AStaticMeshActor> ActorItr(GetWorld()); ActorItr; ++ActorItr)
{
AStaticMeshActor* Mesh = *ActorItr;
FString str1 = ActorItr->GetName();
GEngine->AddOnScreenDebugMessage(-1, 5.f, FColor::Green, FString::Printf(TEXT("%s"), *str1));
FString str2 = ActorItr->GetActorLocation().ToString();
GEngine->AddOnScreenDebugMessage(-1, 5.f, FColor::Green, FString::Printf(TEXT("%s"), *str2));
}
//判断是否实现某个接口
template<class T>
FORCEINLINE bool UObject::Implements() const
{
UClass const* const MyClass = GetClass();
return MyClass && MyClass->ImplementsInterface(T::StaticClass());
}
接口
各种说明符
注:此处建议看官方文档
类说明符
关键词,用于在声明UClasses时指定类相对于引擎和编辑器的各个方面的行为。
https://docs.unrealengine.com/4.27/zh-CN/ProgrammingAndScripting/GameplayArchitecture/Classes/Specifiers/
UFunction声明
UFunction 是虚幻引擎4(UE4)反射系统可识别的C++函数。UObject 或蓝图函数库可将成员函数声明为UFunction,方法是将 UFUNCTION 宏放在头文件中函数声明上方的行中。宏将支持 函数说明符 更改UE4解译和使用函数的方式。
https://docs.unrealengine.com/4.27/zh-CN/ProgrammingAndScripting/GameplayArchitecture/Functions/
属性UPROPERTY
https://docs.unrealengine.com/4.27/zh-CN/ProgrammingAndScripting/GameplayArchitecture/Properties/
USTRUCT([Specifier, Specifier, ...])
struct FStructName
{
GENERATED_BODY()
};
https://docs.unrealengine.com/4.27/zh-CN/ProgrammingAndScripting/GameplayArchitecture/Structs/
杂项知识点
在.h中声明你的类:如果你的类继承自UObject
,你的类名上方需要加入
UCLASS()
宏。同时,你需要在类体的第一行添加GENERATED_UCLASS_BODY()
宏,或者GENERATED_BODY()
宏。前者需要手动实现一个带有const FObject Initializer&
参数的构造函数。后者需要手动实现一个无参数构造函数。注意
笔者说的是“实现”而非声明。
UBlueprintAsyncActionBase
异步蓝图节点
IInputProcessor
输入类(不阻塞不吞噬输入类型)
反射方式获取类属性设置属性
UYourClassName* YourClassName = NewObject<UYourClassName>();
UClass* YourClassNameClass = YourClassName->GetClass();
//获取类名称
FString ClassName = YourClassNameClass->GetName();
UE_LOG(LogTemp, Warning, TEXT("你的类名是 %s."),*ClassName);
//获取类标记
bool bHasMinimalAPI = YourClassNameClass->HasAnyClassFlags(EClassFlags::CLASS_MinimalAPI);
//类属性遍历
for (FProperty* Property = YourClassNameClass->PropertyLink; Property; Property = Property->PropertyLinkNext)
{
//获取属性名称
FString PropertyName = Property->GetName();
//获取属性类型
FString PropertyType = Property->GetCPPType();
//检测类里面是否存在FString类型
if (PropertyType == "FString")
{
FStrProperty* StringProperty = CastField<FStrProperty>(Property);
void* Addr = StringProperty->ContainerPtrToValuePtr<void>(YourClassName);
FString PropertyValue = StringProperty->GetPropertyValue(Addr);
//获取属性元数据
FString CategoryName = StringProperty->GetMetaData(TEXT("Category"));
StringProperty->SetPropertyValue(Addr,"SettingValue");
FString PropertyValueAfterSetting = StringProperty->GetPropertyValue(Addr);
}
}
//类方法遍历
for (TFieldIterator<UFunction> IteratorOfFunction(YourClassNameClass); IteratorOfFunction; ++IteratorOfFunction)
{
UFunction* Function = *IteratorOfFunction;
//获取方法名称
FString FunctionName = Function->GetName();
//获取方法标记
EFunctionFlags FunctionFlags = Function->FunctionFlags;
for (TFieldIterator<FProperty> IteratorOfParam(Function); IteratorOfParam; ++IteratorOfParam)
{
FProperty* Param = *IteratorOfParam;
FString ParamName = Param->GetName();
FString ParamType = Param->GetCPPType();
EPropertyFlags ParamFlags = Param->GetPropertyFlags();
}
}
//获取父类的名称
UChildClassName* MiddleYourClassName = NewObject<UChildClassName>();
UClass* ParentClass = MiddleYourClassName->GetClass()->GetSuperClass();
FString ParentClassName = ParentClass->GetName();
//判断一个类是否是另一个类子类
UClass* Class1 = UChildClassName::StaticClass();
if (Class1->IsChildOf(Class2))
{
UE_LOG(LogTemp, Warning, TEXT("Class1 is Class2's child."));
}
//查找特定类的所有子类
TArray<UClass*> ClassResults;
GetDerivedClasses(UYourClassName::StaticClass(), ClassResults, true);
for (int32 Index = 0; Index < ClassResults.Num(); Index++)
{
UClass* ClassResult = ClassResults[Index];
FString ClassResultName = ClassResult->GetName();
}
//查找由特定类对象
UYourClassSpecial* GMS = NewObject<UYourClassSpecial>(this, FName("GSM1"));
TArray<UObject*> ObjectResults;
GetObjectsOfClass(UYourClassSpecial::StaticClass(), ObjectResults, false);
for (UObject* ObjectResult : ObjectResults)
{
FString ObjectResultName = ObjectResult->GetName();
}
//根据字符串查找相应的类
UClass* FindedClass = FindObject<UClass>(ANY_PACKAGE, *FString("UYourClass"), true);
if (FindedClass)
{
UE_LOG(LogTemp, Warning, TEXT("已找到UYourClass类"));
}
//根据字符串查找枚举
UEnum* Enum = FindObject<UEnum>(ANY_PACKAGE, *FString("EnumYourType"), true);
if (Enum)
{
UE_LOG(LogTemp, Warning, TEXT("找到EnumYourType枚举"));
//遍历枚举项名称
for (int32 Index = 0; Index < FindedEnum->NumEnums(); Index++)
{
FString EnumItemName = FindedEnum->GetNameStringByIndex(Index);
//undo
}
}
//通过名称查找蓝图类
UBlueprint* Blueprint = FindObject<UBlueprint>(ANY_PACKAGE, *FString("BP_BlueprintClass"));
if (Blueprint)
{
//判断该类是蓝图类,还是Native类
if (FindedBlueprint->IsNative())
{
UE_LOG(LogTemp, Warning, TEXT("BP_BlueprintClass是原生类"));
}
else
{
UE_LOG(LogTemp, Warning, TEXT("BP_BlueprintClass是蓝图类"));
}
}
//遍历所有类
FString AllClassNames = "";
for (TObjectIterator<UClass> ClassIt; ClassIt; ++ClassIt)
{
FString InterClassName = ClassIt->GetName();
AllClassNames += InterClassName;
}
//根据名称获取类方法
UGoodMiddleYourClassName* GoodMiddleYourClassName = NewObject<UGoodMiddleYourClassName>();
UClass* GoodMiddleYourClassNameClass = GoodMiddleYourClassName->GetClass();
if (GoodMiddleYourClassNameClass)
{
UFunction* PlayFunction = GoodMiddleYourClassNameClass->FindFunctionByName(TEXT("Play"), EIncludeSuperFlag::ExcludeSuper);
if (PlayFunction)
{
FString PlayFunctionName = PlayFunction->GetName();
UE_LOG(LogTemp, Warning, TEXT("Function with name:%s has finded in GoodMiddleYourClassNameClass"),*PlayFunctionName);
//通过反射调用类方法
//1.给所有方法参数分配空间并初始化为0
uint8* AllFunctionParam = static_cast<uint8*>(FMemory_Alloca(PlayFunction->ParmsSize));
FMemory::Memzero(AllFunctionParam, PlayFunction->ParmsSize);
//2.给所有方法参数赋值
for (TFieldIterator<FProperty> IteratorOfFunctionParam(PlayFunction); IteratorOfFunctionParam; ++IteratorOfFunctionParam)
{
FProperty* FunctionParam = *IteratorOfFunctionParam;
FString FunctionParamName = FunctionParam->GetName();
if (FunctionParamName == FString("InGame"))
{
*FunctionParam->ContainerPtrToValuePtr<FString>(AllFunctionParam) = "Ball";
}
}
//3.调用方法
GoodMiddleYourClassName->ProcessEvent(PlayFunction, AllFunctionParam);
}
//Function.invoke
UFunction* GoHomeFunction = GoodMiddleYourClassNameClass->FindFunctionByName(TEXT("YourFunction"), EIncludeSuperFlag::ExcludeSuper);
if (GoHomeFunction)
{
//1.给所有方法参数分配空间并初始化为0
uint8* AllFunctionParam = static_cast<uint8*>(FMemory_Alloca(GoHomeFunction->ParmsSize));
FMemory::Memzero(AllFunctionParam, GoHomeFunction->ParmsSize);
//2.创建FFrame
FFrame Frame(nullptr, GoHomeFunction, &AllFunctionParam);
//3.调用Invoke
GoHomeFunction->Invoke(GoodMiddleYourClassName, Frame, &AllFunctionParam + GoHomeFunction->ReturnValueOffset);
//4.获取返回值
int* ResultValue = (int*)(&AllFunctionParam + GoHomeFunction->ReturnValueOffset);
UE_LOG(LogTemp, Warning, TEXT("YourFunction方法的返回值是 %d"), *ResultValue);
}
}
文件读写访问
虚幻引擎提供了与平台无关的文件读写与访问接口,即FPlatformFileManager
,该类在PlatformFilemanager.h
中,Core模块下
FPlatformFileManager::Get()->GetPlatformFile();
文件拷贝
提供文件目录和文件的拷贝操作:
CopyDirectoryTree
递归拷贝某个目录;
CopyFile
拷贝当前文件。
文件创建
提供创建文件和目录的操作,目录创建成功或者目录已经存在
都会返回真:
CreateDirectory
创建目录;
CreateDirectoryTree
创建一个目录树,即给定一个路径字符串,如果对应路径的父目录不存在,也会被创建出来。
文件删除
删除指定目录或文件,成功删除返回真,否则失败:
DeleteDirectory
删除指定目录;
DeleteDirectoryRecursively
递归删除指定目录;
DeleteFile
删除指定文件。
文件移动
MoveFile
移动文件
获取文件所对应的属性
提供对文件、目录的属性访问操作:
DirectoryExists
检查目录是否存在;
FileExists
检查文件是否存在;
GetStateData
获得文件状态信息,返回FFileStatData类型对象,这个对象其实包含了足够的状态信息,
GetAccessTimeStamp
获得当前文件上一次访问的时间;
SetTimeStamp
设置文件的修改时间;
FileSize
获得文件大小,如果文件不存在返回-1;
IsReadOnly
文件是否只读。
文件遍历函数
该类函数都需要传入一个FDirectoryVisitor
或FDirectoryStatVisitor
对象作为参数。你可以创造一个类继承自该类,然后重写Visit
函数。每当遍历到一个文件或者目录时,遍历函数会调用Visitor对象的Visit函数以通知执行自定义的逻辑:IterateDirectory
遍历某个目录;
IterateDirectoryRecursively
递归遍历某个目录;IterateDirectoryStat
遍历文件目录状态,Visit函数参数为状态对象而非路径字符串;IterateDirectoryStatRecursively
同上,递归遍历。
文件读写
OpenRead
打开一个文件用于读取,返回IFileHandle类型的句柄用于读取;
OpenWrite
打开一个文件用于写入,返回IFileHandle类型的句柄。同时,针对一些极其普遍的需求,虚幻引擎提供了一套更简单的方式用于读写文件内容,即FFileHelper类,位于CoreMisc头文件中,提供以下静态函数:LoadFileToArray
直接将路径指定的文件读取到一个TArray类型的二进制数组中;LoadFileToString
直接将路径指定的文本文件读取到一个FString
类型的字符串中。请注意,字符串有长度限制,不要试图读取超大文本文件;
SaveArrayToFile
保存一个二进制数组到文件中;
SaveStringToFile
保存一个字符串到指定文件中;
CreateBitmap
在硬盘中创建一个BMP
文件;
LoadANSITextFileToStrings
读取一个ANSI
编码的文本文件到一个字
符串数组中,每行对应一个FString
类型的对象。
配置文件
虚幻引擎提供的专门读写配置文件的类——GConfi
。
写配置
GConfig->SetString(
TEXT("MySection"),
TEXT("Name"),
TEXT("李白"),
FPaths::GameDir()/ "MyConfig.ini");
读配置
FString Result;
GConfig->GetString(
TEXT("MySection"),
TEXT("Name"),
Result,
FPaths::GameDir() / "MyConfig.ini");
Slate部分知识点
Slot获取
通过Expose的方式将其暴露出去,然后达到更改变量值去修改Slot属性的目的
Bind UMG
UPROPERTY(BlueprintReadOnly, meta = (BindWidget))
编辑器添加按键
在Commond位置添加对应按键
在注册命令的位置,把命令添加进MainFrame
UI_COM
MAND(PluginAction, "SwitchLanguage", "SwitchLanguage in editor", EUserInterfaceActionType::Button, FInputChord(EKeys::O));
IMainFrameModule& MainFrameModule = FModuleManager::Get().LoadModuleChecked<IMainFrameModule>("MainFrame");
MainFrameModule.GetMainFrameCommandBindings()->Append(PluginCommands.ToSharedRef());
模块获取
FContentBrowserModule& ContentBrowserModule = FModuleManager::GetModuleChecked<FContentBrowserModule>("ContentBrowser");
设备切换
class InputDetectionProcessor : public IInputProcessor
{
public:
virtual bool HandleAnalogInputEvent(FSlateApplication& SlateApp, const FAnalogInputEvent& InAnalogInputEvent) override;
virtual bool HandleKeyDownEvent(FSlateApplication& SlateApp, const FKeyEvent& InKeyEvent) override;
virtual bool HandleMouseMoveEvent(FSlateApplication& SlateApp, const FPointerEvent& MouseEvent) override;
virtual bool HandleMouseWheelOrGestureEvent(FSlateApplication& SlateApp, const FPointerEvent& InWheelEvent, const FPointerEvent* InGestureEvent) override;
virtual bool HandleMouseButtonDownEvent(FSlateApplication& SlateApp, const FPointerEvent& MouseEvent) override;
virtual void Tick(const float DeltaTime, FSlateApplication& SlateApp, TSharedRef<ICursor> Cursor) override;
public:
FOnInputDeviceChangedDelegate InputDeviceChangedDelegate;
};
if (FSlateApplication::IsInitialized())
{
InputProcessor = MakeShared<InputDetectionProcessor>();
auto& SlateApplication= FSlateApplication::Get();
SlateApplication.RegisterInputPreProcessor(InputProcessor);
InputProcessor->InputDeviceChangedDelegate.BindRaw(this, &FYourModule::OnInputDeviceChanged);
}
ENum字符串与值直接的转行
通常情况下,网络上的文章都是以下面方式获取的,但是UE5会报以下警告ANY_PACKAGE has been deprecated. Either use full path name of objects (including classes) or provide a valid Outer for *FindObject* functions
,因为,本着程序员的消出警告的开发原则,小编还是采用了新的方式来获取。
FString getBodyEnumAsString(EBodyPosition value)
{
const UEnum* EnumPtr = FindObject<UEnum>(ANY_PACKAGE, TEXT("EBodyPosition"), true);
if (!EnumPtr) return FString("Invalid");
return EnumPtr->GetEnumName((int32)value);
}
无警告方式:
//通过枚举值获取对应字符串
template<typename TEnum>
FString GameDataHelper::GetEnumValueAsString(const TCHAR* PathName, TEnum Value)
{
const UEnum* EnumPtr = FindObject<UEnum>(nullptr, PathName, true);
if (!EnumPtr)
{
Print("UEnum is not InValid type. GetEnumValueAsString");
return FString("Invalid");
}
return EnumPtr->GetNameStringByValue((int64)Value);
}
//通过对应字符串获取枚举值
template<typename TEnum>
TEnum GameDataHelper::GetEnumValueFromString(const TCHAR* PathName, FString Value)
{
const UEnum* EnumPtr = FindObject<UEnum>(nullptr, PathName, true);
if (!EnumPtr)
{
Print("UEnum is not InValid type . GetEnumValueFromString");
return TEnum(0);
}
return (TEnum)EnumPtr->GetIndexByNameString(Value);
}
传参示例:
UENUM()
enum class ECultureTeam : uint8
{
EN = 0,
ZH = 1,
MAX = 2
};
GetEnumValueAsString<ECultureTeam>(TEXT("/Script/Game.ECultureTeam"), CurrentCulture)
GetEnumValueFromString<ECultureTeam>(TEXT("/Script/Game.ECultureTeam")
TEXT("/Script/Game.ECultureTeam"传参中,Game对应枚举所在的模块,ECultureTeam则是自己的枚举类型
当然,官方肯定也有自己的方法:
命令
找个StartupModule调用就行
不带参命令
IConsoleManager::Get().RegisterConsoleCommand(
TEXT("YourCommandName"),
TEXT("Description of your command."),
FConsoleCommandDelegate::CreateStatic(&UYourClass::YourFunction),
ECVF_Default
);
带参命令
IConsoleManager::Get().RegisterConsoleCommand(
TEXT("YourCommandName"),
TEXT("Description of your command."),
FConsoleCommandWithArgsDelegate::CreateStatic(&TestCommandWithParam),
ECVF_Default
);
宏实例
//不带参
#define REGISTERCONSOLECOMMAND(FunctionName) \
IConsoleManager::Get().RegisterConsoleCommand( \
TEXT("Slash." #FunctionName), \
TEXT(#FunctionName " is used auto register console command."), \
FConsoleCommandDelegate::CreateStatic(&UMyFunctionLibrary::FunctionName), \
ECVF_Default \
)
//带参
#define REGISTERCONSOLECOMMANDWITHPARAM(FunctionName) \
IConsoleManager::Get().RegisterConsoleCommand( \
TEXT("Slash."#FunctionName"_WithParam"), \
TEXT(#FunctionName" is used auto register console command."),\
FConsoleCommandWithArgsDelegate::CreateStatic(&FunctionName), \
ECVF_Default \
)
示例:
#pragma once
#include "Debug.h"
#include "ConsloCommandLibrary.generated.h"
#define REGISTERCONSOLECOMMAND(FunctionName) \
IConsoleManager::Get().RegisterConsoleCommand( \
TEXT("Slash." #FunctionName), \
TEXT(#FunctionName " is used auto register console command."), \
FConsoleCommandDelegate::CreateStatic(&UCommonFunctionLibrary::FunctionName), \
ECVF_Default \
)
#define REGISTERCONSOLECOMMANDWITHPARAM(FunctionName) \
IConsoleManager::Get().RegisterConsoleCommand( \
TEXT("Slash."#FunctionName"_WithParam"), \
TEXT(#FunctionName" is used auto register console command."),\
FConsoleCommandWithArgsDelegate::CreateStatic(&FunctionName), \
ECVF_Default \
)
UCLASS()
class SLASH_API UCommonFunctionLibrary final : public UBlueprintFunctionLibrary
{
GENERATED_BODY()
public:
static void RegisterAllCommands()
{
REGISTERCONSOLECOMMAND(TestCommand);
REGISTERCONSOLECOMMANDWITHPARAM(TestCommandWithParam);
}
static void TestCommand()
{
Print("This is my test function");
}
static void TestCommandWithParam(const TArray<FString>& Args)
{
FString Str;
for (auto Arg : Args)
{
Str += Arg;
}
Print(Str);
}
};
然后再mode注册命令
获取线程名字
uint32 ThreadId = FPlatformTLS::GetCurrentThreadId();
FString ThreadName = FThreadManager::Get().GetThreadName(ThreadId);