UE4C++代码编写过程中常用的方法代码片段(方便小编做个CV程序员)

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文件是否只读。

文件遍历函数

该类函数都需要传入一个FDirectoryVisitorFDirectoryStatVisitor对象作为参数。你可以创造一个类继承自该类,然后重写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);
好的,下面是一个简单的Ue4 C++ Replay编写案例: 1. 首先,在UE4创建一个新的C++项目,并创建一个名为MyGameInstance的GameInstance子类。 2. 在MyGameInstance.h文件添加以下代码: ```cpp #pragma once #include "Engine/GameInstance.h" #include "MyGameInstance.generated.h" UCLASS() class MYPROJECT_API UMyGameInstance : public UGameInstance { GENERATED_BODY() public: UFUNCTION(BlueprintCallable) void StartRecording(); UFUNCTION(BlueprintCallable) void StopRecording(); UFUNCTION(BlueprintCallable) void StartReplay(); private: FString ReplayFilename; }; ``` 3. 在MyGameInstance.cpp文件实现StartRecording、StopRecording和StartReplay函数。下面是一个简单的实现示例: ```cpp #include "MyGameInstance.h" #include "Engine/Engine.h" #include "EngineUtils.h" #include "GameFramework/PlayerController.h" #include "Misc/Paths.h" #include "Misc/FileHelper.h" #include "Engine/LocalPlayer.h" #include "GameFramework/PlayerState.h" #include "GameFramework/GameStateBase.h" #include "GameFramework/WorldSettings.h" void UMyGameInstance::StartRecording() { FString CurrentDateTime = FDateTime::Now().ToString(TEXT("%Y-%m-%d-%H-%M-%S")); ReplayFilename = FPaths::ProjectSavedDir() / FString(TEXT("Replays/")) + CurrentDateTime + TEXT(".replay"); for (TActorIterator<APlayerController> It(GetWorld()); It; ++It) { APlayerController* PlayerController = *It; if (PlayerController->IsLocalPlayerController()) { ULocalPlayer* LocalPlayer = Cast<ULocalPlayer>(PlayerController->Player); if (LocalPlayer) { FString AdditionalData = FString::Printf(TEXT("PlayerName=%s"), *LocalPlayer->GetPlayerName()); GetWorld()->DemoNetDriver->StartRecording(ReplayFilename, false, AdditionalData); break; } } } } void UMyGameInstance::StopRecording() { GetWorld()->DemoNetDriver->StopRecording(); } void UMyGameInstance::StartReplay() { if (FFileHelper::FileExists(*ReplayFilename)) { for (TActorIterator<APlayerController> It(GetWorld()); It; ++It) { APlayerController* PlayerController = *It; if (PlayerController->IsLocalPlayerController()) { ULocalPlayer* LocalPlayer = Cast<ULocalPlayer>(PlayerController->Player); if (LocalPlayer) { FString AdditionalData = FString::Printf(TEXT("PlayerName=%s"), *LocalPlayer->GetPlayerName()); GetWorld()->DemoNetDriver->PlayDemoFromFile(ReplayFilename, AdditionalData); break; } } } } } ``` 4. 在UE4创建一个新的Blueprint类,并将其命名为ReplayActor。在ReplayActor添加以下代码: ```cpp UCLASS() class MYPROJECT_API AReplayActor : public AActor { GENERATED_BODY() public: AReplayActor(); protected: virtual void BeginPlay() override; private: UPROPERTY(VisibleAnywhere) UStaticMeshComponent* StaticMeshComponent; UPROPERTY(EditAnywhere) UMaterialInterface* Material; void OnReplayFinished(); }; ``` 5. 在ReplayActor.cpp文件实现OnReplayFinished和BeginPlay函数。下面是一个简单的实现示例: ```cpp #include "ReplayActor.h" #include "Components/StaticMeshComponent.h" #include "Materials/MaterialInterface.h" #include "Kismet/GameplayStatics.h" #include "MyGameInstance.h" AReplayActor::AReplayActor() { PrimaryActorTick.bCanEverTick = false; StaticMeshComponent = CreateDefaultSubobject<UStaticMeshComponent>(TEXT("StaticMeshComponent")); StaticMeshComponent->SetCollisionEnabled(ECollisionEnabled::NoCollision); RootComponent = StaticMeshComponent; } void AReplayActor::BeginPlay() { Super::BeginPlay(); if (UMyGameInstance* GameInstance = Cast<UMyGameInstance>(GetGameInstance())) { FDelegateHandle ReplayFinishedHandle = GameInstance->GetWorld()->AddOnWorldCleanup(FWorldCleanup::FOnWorldCleanupDelegate::CreateUObject(this, &AReplayActor::OnReplayFinished)); } if (Material) { StaticMeshComponent->SetMaterial(0, Material); } } void AReplayActor::OnReplayFinished() { Destroy(); } ``` 6. 在UE4创建一个新的关卡,并将其命名为ReplayLevel。在ReplayLevel添加一个ReplayActor,并将其Material属性设置为一个你喜欢的材质。 7. 在UE4创建一个新的蓝图,并将其命名为ReplayController。在ReplayController添加以下事件: - Event Begin Play:调用MyGameInstance的StartRecording函数来开始记录Replay。 - Input Action Replay:调用MyGameInstance的StartReplay函数来开始回放Replay。 8. 在ReplayController添加一个Input Action,并将其命名为Replay。在Replay Action的Details面板将Key设置为R。 9. 在UE4运行ReplayLevel,并在ReplayController蓝图按下R键来开始记录Replay。完成后,按下R键再次开始回放Replay。 上面是一个简单的UE4 C++ Replay编写案例。您可以根据您的需求和项目的要求进行修改和扩展。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值