UE5 C++(三)— 基本用法(生命周期、日志、基础变量)


忘记说了每次在Vscode修改后C++脚本后,需要编译一下脚本,为了方便我是点击这里编译脚本
在这里插入图片描述

生命周期

Actor 生命周期官方文档中有详细介绍,这里只介绍常用的。

常用声明周期函数:

  • BeginPlay() :游戏开始时执行一次
  • Tick(float DeltaTime) :游戏运行时每帧执行一次
  • EndPlay(const EEndPlayReason::Type EndPlayReason) :游戏结束或者切换关卡时执行一次

集成自AGameMode实现类AMyGameMode

#pragma once

#include "CoreMinimal.h"
#include "MyGameState.h"
#include "MyHUD.h"
#include "MyPawn.h"
#include "MyPlayerController.h"
#include "MyPlayerState.h"
#include "GameFramework/GameMode.h"
#include "MyGameMode.generated.h"

UCLASS()
class DEMO_API AMyGameMode : public AGameMode
{
	GENERATED_BODY()
	AMyGameMode();

public:
	// 游戏开始时执行一次
	virtual void BeginPlay() override;
	//游戏运行时每帧执行一次
	virtual void Tick(float DeltaTime) override;
	//游戏结束h或者切换关卡时执行一次
	virtual void EndPlay(const EEndPlayReason::Type EndPlayReason) override;
};

#include "MyGameMode.h"

AMyGameMode::AMyGameMode()
{
    DefaultPawnClass = AMyPawn::StaticClass();
    HUDClass = AMyHUD::StaticClass();
    PlayerControllerClass = AMyPlayerController::StaticClass();
    GameStateClass = AMyGameState::StaticClass();
    PlayerStateClass = AMyPlayerState::StaticClass();
}

void AMyGameMode::BeginPlay()
{
    Super::BeginPlay();
}

void AMyGameMode::Tick(float DeltaTime)
{
    Super::Tick(DeltaTime);
}

void AMyGameMode::EndPlay(const EEndPlayReason::Type EndPlayReason)
{
    Super::EndPlay(EndPlayReason);
}

日志打印

Outlog打印

void AMyGameMode::BeginPlay()
{
    Super::BeginPlay();

    // LogTemp : 临时日志,不会保存到文件中
    // Warning : 警告日志,黄色 记录级别
    // TEXT : 打印内容
    // 日志级别常用三种:Display、Warning、Error
    UE_LOG(LogTemp, Display, TEXT("Hello World!"));
    UE_LOG(LogTemp, Warning, TEXT("Hello World!"));
    UE_LOG(LogTemp, Error, TEXT("Hello World!"));
}

在这里插入图片描述

屏幕打印

void AMyGameMode::BeginPlay()
{
    Super::BeginPlay();
    //打印到屏幕上
    GEngine->AddOnScreenDebugMessage(-1, 5.f, FColor::Red, TEXT("Hello World!"));
}

在这里插入图片描述

基础变量类型

打开关卡蓝图
在这里插入图片描述
查看变量类型
在这里插入图片描述
在C++脚本中声明

UCLASS()
class DEMO_API AMyGameMode : public AGameMode
{
	GENERATED_BODY()
	AMyGameMode();

public:
	// 游戏开始时执行一次
	virtual void BeginPlay() override;
	// 游戏运行时每帧执行一次
	virtual void Tick(float DeltaTime) override;
	// 游戏结束h或者切换关卡时执行一次
	virtual void EndPlay(const EEndPlayReason::Type EndPlayReason) override;

	/****** 声明变量类型 ********/
	// 布尔类型
	bool m_IsBool;
	// 整型32位
	int32 m_Int32;
	// 整型64位
	int64 m_Int64;
	// 字节类型
	BYTE m_Byte;
	// FString字符串
	FString m_String;
	// FName字符串
	FName m_Name;
	//FText字符串
	FText m_Text;
	//FVector 向量类型  x,y,z轴
	FVector m_Vector;
	//FRotator 旋转类型  x轴旋转Roll,y轴旋转Pitch,z轴旋转Yaw
	FRotator m_Rotator;
	//FTransform 变换类型  位置(Position)+旋转(Rotation)+缩放(Scale)
	FTransform m_Transform;
};

在这里插入图片描述

FString、FName 和 FText,三者之间的区别

  • FName:表示名称,不区分大小写,不可更改
    • 引擎中的资源名称都是FName类型,

    • 通过一个轻型系统重复使用字符串,FName创建时会根据内容创建一个Hash值,且同样的内容只会存储一次。

    • 通过Hash值在进行FName的查找和访问时速度较快,而在比较的时,也不需要比较字符串内容,直接比较Hash值来区分不同FName字符串。

    • 另外两种字符串到FName的转换(特别注意的是,FText不能直接转换到FName,可先转换为FString,再转换为FName):

FString str = TEXT("Hello world~");
FText txt = LOCTEXT("keyName", "theValue");
FText txtNS = NSLOCTEXT("TextNameSpace", "keyName", "theValue");
 
// FString 转 FName:不可靠,丢失大小写信息
FName name1 = FName(*str);

FString strFromTxt = txt.ToString();
// FText 先转 FString,再转 FName:不可靠,丢失大小写信息,丢失本地化信息可能导致语言转换的潜在风险
FName name2 = FName(*strFromTxt);
  • FString:最接近std::string,着重在于字符串的操作
    • 提供了大量对字符串的操作接口,是三者中唯一可修改的字符串类型,
    • 也正因如此,FString对比其它两种字符串来说消耗更高,性能更低。
    • 另外两种字符串到FString的转换:
FName name = TEXT("I am Frank~");
FText txt = LOCTEXT("keyName", "theValue");
FText txtNS = NSLOCTEXT("TextNameSpace", "keyName", "theValue");

// FName 转 FString:可靠
FString str1 = name.ToString();
// FText 转 FString:不可靠,丢失本地化信息可能导致语言转换的潜在风险
FString str2 = txt.ToString();
  • FText:着重在于显示与本地化,显示可理解玩家能直接看到的信息
    • 本地化即多语言的处理,不可更改。
    • 相较于另外两种类型,FText会更加的臃肿,但提供了优秀的本地化功能。
    • 另外两种字符串到FText的转换:
FString str = TEXT("Hello world~");
FName name = TEXT("I am Hello~");

// FString 转 FText:可靠
FText txt1 = FText::FromString(str);
// FName 转 FText:可靠
FText txt2 = FText::FromName(name);

基础数据类型打印

//基础数据类型的输出打印
int32 MyInt=10;
float MyF1oat=5.0f;
bool MyBool=true;
char MyChar=’A';
FString MyStringl=TEXT("MyStringl");
FVector MyVector=FVector(0,0,0);
//打印
UE_LOG(LogTemp,Warning,TEXT("%d"),MyInt);
UE_LOG(LogTemp,Warning,TEXT("%f"),MyF1oat);
UE_LOG(LogTemp,Warning,TEXT("%d"),MyBoo1);
UE_LOG(LogTemp,Warning, TEXT("%c"),MyChar);
UE_LOG(LogTemp,Warning,TEXT("%s"),*MyString1);
UE_LOG(LogTemp,Warning,TEXT("%s"),*MyVector.ToString());
<think>好的,用户说他是UE5 C++开发者,我需要针对他的背景来回答之前的警告问题。之前他提到的是关于变量未使用的警告,现在需要结合UE5 C++的具体情况来分析。 首先,UE5C++项目通常会有自己的编码规范和宏,比如可能使用UE_LOG进行日志输出,或者GEngine->AddOnScreenDebugMessage来显示信息。用户可能在代码中声明了变量但没有使用它们,导致编译器警告。 接下来,要考虑UE5特有的情况,比如可能在蓝图中使用的UPROPERTY变量,如果没有正确标记,或者没有在蓝图中使用,也会出现未使用的警告。另外,UE5的代码生成工具可能对变量使用有特殊要求,比如必须初始化或显式标记为未使用。 然后,需要回顾之前的解决方案,将其适配到UE5的上下文中。例如,检查变量是否在UE日志系统或调试信息中使用,或者是否正确暴露给蓝图。同时,可能需要提到UE5的宏如ensureMsgf或check来使用变量,或者使用UNUSED宏来显式标记未使用的变量以避免警告。 还要注意UE5的编码规范,比如变量命名通常带有前缀,如b表示布尔,或者使用驼峰命名法,这可能影响变量声明的正确性。另外,如果变量是在头文件中声明但未在源文件中使用,也可能导致警告,需要检查头文件中的声明是否必要。 最后,可能需要提醒用户关于UE5的热重载功能,如果在编辑器中修改代码后没有正确编译或重新加载,可能会导致变量看似未使用的情况,需要确保编译过程完成。同时,建议用户查看输出日志,确定警告的具体位置和上下文,以便更精准地解决问题。</think>$\textbf{针对UE5 C++开发者的变量未使用警告解决方案}$ $\boxed{\text{核心问题}}$:在UE5 C++项目中,变量被赋值但未被后续代码引用。以下是$\textbf{专为UE引擎优化的解决策略}$: --- $\textbf{步骤1:验证UE特定使用场景}$ 1. $\textbf{蓝图交互检查}$:若变量涉及`UPROPERTY` ```cpp // 错误案例:暴露给蓝图但未实际使用 UPROPERTY(VisibleAnywhere) float MinSqDist; // 仅声明未使用 // 正确做法:在C++代码或蓝图中必须有读取操作 void YourActor::Tick(float DeltaTime) { if (MinSqDist > Threshold) {...} // 添加实际使用 } ``` 2. $\textbf{调试输出规范}$:使用UE专用日志系统 ```cpp // 必须包含头文件 #include "Kismet/KismetSystemLibrary.h" // 在赋值后添加调试输出 UKismetSystemLibrary::PrintString( GetWorld(), FString::Printf(TEXT("最小距离:%f,索引:%d"), MinSqDist, MinSqDistIdx), true, // 显示到屏幕 false, // 不写入日志文件 FColor::Green, 2.0f // 显示时长 ); ``` --- $\textbf{步骤2:处理引擎编译特性}$ 3. $\textbf{抑制警告的UE标准方法}$(慎用): ```cpp // 使用UE_UNUSED宏显式标记 UE_UNUSED(MinSqDist); UE_UNUSED(MinSqDistIdx); // 或使用C++17特性(需启用对应编译标准) [[maybe_unused]] float MinSqDist = JuLi[idx]; ``` 4. $\textbf{热重载陷阱}$:在编辑器运行中修改代码后,必须: - 完全编译(非热重载) - 关闭"Live Coding"功能测试 - 清除Intermediate/Binaries目录 --- $\textbf{步骤3:优化代码结构}$ 5. $\textbf{基于UE的算法优化}$: ```cpp // 用TArray内置方法替代手动查找 TArray<float> JuLiArray; int32 MinIndex = INDEX_NONE; // UE专用无效索引标识 const float MinVal = JuLiArray.FindMinIndex(MinIndex); // 自动获取最小值和索引 // 或使用Algo模板库 auto MinIt = Algo::MinElement(JuLiArray); if (MinIt != JuLiArray.end()) { const int32 FoundIndex = MinIt - JuLiArray.begin(); } ``` 6. $\textbf{异步任务处理}$:若涉及多线程 ```cpp // 错误案例:在AsyncTask中赋值但未同步 AsyncTask(ENamedThreads::GameThread, [this, idx](){ MinSqDist = JuLi[idx]; // 可能未被主线程及时使用 }); // 正确做法:使用原子变量或任务委托 std::atomic<float> MinSqDist_Atomic{0.0f}; AsyncTask(ENamedThreads::AnyBackgroundThreadNormalTask, [&](){ MinSqDist_Atomic.store(JuLi[idx]); }); // 主线程中读取 if (MinSqDist_Atomic.load() > Threshold) {...} ``` --- $\textbf{UE专有注意事项}$: - $\textbf{垃圾回收}$:若变量持有`UObject`指针,需确保: ```cpp UPROPERTY() // 必须标记以防止意外回收 AActor* CachedActor; ``` - $\textbf{序列化}$:检查变量是否需要`SaveGame`标记 ```cpp UPROPERTY(SaveGame) float PersistentValue; // 会被存档系统使用 ``` 通过结合UE5引擎特性处理变量生命周期和多线程场景,可从根本上消除警告并提升代码健壮性。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值