枚举
enum DAY
{
MON=1, TUE, WED, THU, FRI, SAT, SUN
};
位置
GetTransform()/GetActorLocation:获取位置
Actor:
FVector NewLocation = GetActorLocation();
FRotator NewRotation = GetActorRotation();
时间
GetGameTimeSinceCreation();
文字输出
打印到日志
UE_LOG(LogTemp, log, TEXT("普通信息,不会中断程序"));
UE_LOG(LogTemp, Warning, TEXT("警告: %d"), 123);
UE_LOG(LogTemp, Error, TEXT("错误: %f"), 123.0);
UE_LOG(LogTemp, Fatal, TEXT("致命错误: %s"), "Oh no");
DEBUG_LOG("角色速度:%f", Speed);
//DEBUG_LOG会展开成
//UE_LOG(LogTemp, Warning, TEXT("角色速度:%f"), Speed);
多个参数
UE_LOG(LogTemp, log, TEXT("x: %f \ny: %f"), X,Y);
参数解释
UE_LOG(
LogTemp,//一个日志类别,表示临时调试信息
Warning, //日志等级
TEXT("Hello %d"),// 内容
123//`Format` 和 `__VA_ARGS__`(可变参数),替换%d
);
打印到屏幕
首先要检查指针,因为GEngine只在游戏已经开始后才存在。(BeginPlay()、Tick()里是OK的,但构造函数里不行)
if (GEngine){}
下面是两种方式
GEngine->AddOnScreenDebugMessage(-1,3.0f,FColor::Red,TEXT("!"));
FString Name = "Hello World!";
GEngine->AddOnScreenDebugMessage(-1,3.0f,FColor::Red, Name);
参数解释
GEngine->AddOnScreenDebugMessage(
-1, // Key(-1:新建一条,1:覆盖旧的)
3.0f, // 显示时间(3秒),“.0f”表示长存
FColor::Yellow, // 字体颜色
TEXT("Hello World!") // 显示内容
);
清空屏幕
GEngine->ClearOnScreenDebugMessages();
为了防止文字出现在正式版中,应该写在
#if !(UE_BUILD_SHIPPING || UE_BUILD_TEST)
if (GEngine) //这里的代码
{ //不在发布版 (Shipping)
GEngine-> //和测试版 (Test)
} //中运行
#endif
只在开发版(Debug) 和 调试版(DebugGame)执行。
创建对象
创建
UCameraComponent* Camera = NewObject<UCameraComponent>(this);
AMyActor* Actor = GetWorld()->SpawnActor<AMyActor>();
类的引用:TSubclassOf
UPROPERTY(EditAnywhere)
TSubclassOf<AWeapon> WeaponClass; //在蓝图中选择一个继承AWeapon的类
AWeapon* Weapon = GetWorld()->SpawnActor<AWeapon>(WeaponClass);
遍历场景中的对象
TActorIterator:高效
#include "EngineUtils.h"
//有参构造一个该类型的迭代器It
for (TActorIterator<AMyActor> It(GetWorld()); It; ++It)
{
AMyActor* obj = *It;//用obj接收
}
GetAllActorsOfClass:比较麻烦的是,第三个参数数组只能是AActor,需转类型
TArray<AActor*> FoundActors;//基类数组
UGameplayStatics::GetAllActorsOfClass(GetWorld(),AMyActor::StaticClass(), FoundActors);
TArray<AMyActor*> MyActors;//目标类数组
for (AActor* Actor : FoundActors)
{
AMyActor* AyActor = Cast<AMyActor>(Actor);//把基类转成目标类
if (AyActor)
{
MyActors.Add(AyActor);
}
}
加载资源
//加载骨骼网格体
static ConstructorHelpers::FObjectFinder<USkeletalMesh> TankMeshAsset(TEXT("/Game/SK_West_Tank_M1A1Abrams.SK_West_Tank_M1A1Abrams"));
if (TankMeshAsset.Succeeded())
{
GetMesh()->SetSkeletalMesh(TankMeshAsset.Object);
}
//加载静态网格体
static ConstructorHelpers::FObjectFinder<UStaticMesh> TankDamagedMeshAsset(TEXT("/Game/West_Tank_M1A1Abrams/Damaged/SM_West_Tank_M1A1Abrams_Damaged.SM_West_Tank_M1A1Abrams_Damaged"));
if (TankDamagedMeshAsset.Succeeded())
{
TankDamagedMesh->SetStaticMesh(TankDamagedMeshAsset.Object);
}
//加载动画蓝图
static ConstructorHelpers::FClassFinder<UMyVehicleAnimationInstance> AnimInstanceAsset(TEXT("/Game/ABP_MyVehicleAnimationInstance.ABP_MyVehicleAnimationInstance_C'"));
if (TankDamagedMeshAsset.Succeeded())
{
GetMesh()->SetAnimInstanceClass(AnimInstanceAsset.Class);
}
//加载增强输入上下文
static ConstructorHelpers::FObjectFinder<UInputMappingContext> ContextObj(TEXT("/Game/IMC_MyTank.IMC_MyTank"));
if (ContextObj.Succeeded() && ContextObj.Object) { MappingContext = ContextObj.Object; }
static ConstructorHelpers::FObjectFinder<UInputAction> IA_Move(TEXT("/Game/IA_Move.IA_Move"));
if (IA_Move.Succeeded() && IA_Move.Object) { MoveAction = IA_Move.Object; }
委托
| 类型 | 描述 | 关键字 |
|---|---|---|
| 单播委托 | 只能绑定一个函数后绑定覆盖前绑定 | DECLARE_DELEGATE、DECLARE_DELEGATE_OneParam |
| 动态单播委托 | 可暴露给蓝图,绑定一个函数 | DECLARE_DYNAMIC_DELEGATE |
| 多播委托 | 可绑定多个函数 | DECLARE_MULTICAST_DELEGATE |
| 动态多播委托 | 蓝图可绑定多个函数 | DECLARE_DYNAMIC_MULTICAST_DELEGATE |
✅ 1. 单播委托
声明:
DECLARE_DELEGATE(FSimpleDelegate);
DECLARE_DELEGATE_OneParam(FOneParamDelegate, int32);
FSimpleDelegate MyDelegate;
绑定:
MyDelegate.BindUObject(this, &MyClass::MyFunction);//本类,本函数
解绑:
MyDelegate.Unbind();
广播:
if (MyDelegate.IsBound())
{
MyDelegate.Execute();
}
//或
MyDelegate.ExecuteIfBound();
✅ 2. 动态单播委托(可用于蓝图)
声明:
DECLARE_DYNAMIC_DELEGATE(FDynamicSimpleDelegate);
DECLARE_DYNAMIC_DELEGATE_OneParam(FDynamicOneParamDelegate, int32, Param);
FDynamicSimpleDelegate MyDelegate;
绑定:
MyDelegate.BindDynamic(this, &MyClass::MyFunction);
解绑:
MyDelegate.Unbind();
广播:
if (MyDelegate.IsBound())
{
MyDelegate.Execute();
}
✅ 3. 多播委托(单播委托的数组)
声明:
DECLARE_MULTICAST_DELEGATE(FMultiDelegate);
DECLARE_MULTICAST_DELEGATE_OneParam(FMultiDelegateOneParam, int32);
FMultiDelegate MyDelegate;
绑定:
MyDelegate.AddUObject(this, &MyClass::MyFunction);
解绑:
MyDelegate.RemoveAll(this);
广播:
MyDelegate.Broadcast(); // 广播所有绑定者,有参委托就在括号里写参数
✅ 4. 动态多播委托(最常用于蓝图)
声明:
DECLARE_DYNAMIC_MULTICAST_DELEGATE(FDynamicMulticastDelegate);
声明时必须是 UPROPERTY:
UPROPERTY(BlueprintAssignable)
FDynamicMulticastDelegate OnNotify;
绑定:
OnNotify.AddDynamic(this, &MyClass::MyFunction);
解绑:
OnNotify.RemoveDynamic(this, &MyClass::MyFunction);
广播:
OnNotify.Broadcast();
一种 “匿名函数” ——当写代码的时候需要一个函数,可以在原地临时定义一个小函数并立刻传进去,常用于回调函数。
[捕获列表](参数列表) -> 返回类型 {
函数体
};
Lambda 让你临时写函数更方便,不用专门定义一个独立函数
✨ 捕获列表详细
| 写法 | 说明 |
|---|---|
[] | 不捕获任何外部变量 |
[=] | 捕获外部变量(包括 this)按值拷贝 |
[&] | 捕获外部变量 按引用,可以修改它们 |
[this] | 捕获当前类的成员变量 |
[var1, &var2] | 精确指定:var1 按值,var2 按引用 |
FString
FString 的创建方式
1. 直接构造
FString MyStr = TEXT("Hello");
FString MyString1 = FString(TEXT("Hello"));
FString MyString2 = FString(OtherString); // 拷贝构造
2. 类型转换
FString MyStr = MyText.ToString();//从FText
FString MyStr = MyName.ToString();//从FName
3. 字符串拼接
FString Result = FString(TEXT("Hello")) + TEXT(" World");
4. 通过格式化
FString Formatted = FString::Printf(TEXT("Value: %d"), 42);
5. 从其他类型转换
int32 Number = 100;
FString NumString = FString::FromInt(Number);
FText
1. 直接构造
#define LOCTEXT_NAMESPACE "YourNamespace" // 放在文件顶部(通常是.cpp)
FText Text = LOCTEXT("HelloKey", "Hello, World!");
#undef LOCTEXT_NAMESPACE // 放在文件末尾
//`LOCTEXT` 宏依赖于你所在文件中定义了 `LOCTEXT_NAMESPACE` 宏,它是告诉 Unreal "这个文件属于哪个本地化命名空间"。
FText FromNumber = FText::AsNumber(123);
2. 类型转换
FText MyText = FText::FromString(MyStr);//从FString
FText MyText = FText::FromString(FString(TEXT("Hello")));//同上
FText MyText = FText::FromName(MyName);//从FName
FText MyText = FText::FromName(FName("PlayerName"));//同上
FName
1. 直接构造
FName Name = FName("Enemy_001");
2. 类型转换
FName MyName = FName(*Str); //从FString 注意需要用 * 解引用
FName MyName = FName(*Text.ToString());//从FText 用 * 解引用
| 从 | 到 | 转换方法 | 示例 |
|---|---|---|---|
FString | FName | *运算符 | *MyString |
FString | const TCHAR* | *运算符 | *MyString |
const char* | FString | TEXT()宏 | TEXT("string") |
FName | FString | .ToString() | MyName.ToString() |
按键绑定和输入
头文件
public:
// 输入对象
/** 映射上下文*/
UPROPERTY(EditAnywhere, BlueprintReadOnly, Category = Input, meta = (AllowPrivateAccess = "true"))
UInputMappingContext* MappingContext;
/** 输入类 */
UPROPERTY(EditAnywhere, BlueprintReadOnly, Category = Input, meta = (AllowPrivateAccess = "true"))
UInputAction* MoveAction;
/** 触发类 */
UPROPERTY(EditAnywhere, BlueprintReadOnly, Category = Input, meta = (AllowPrivateAccess = "true"))
UInputAction* FireAction;
protected:
//输入函数
UFUNCTION()
void Move_Forward(const FInputActionValue& Value);
UFUNCTION()
void Turn_Right(const FInputActionValue& Value);
UFUNCTION()
void Action_UnFire();
virtual void NotifyControllerChanged() override;//控制器更换时调用
virtual void SetupPlayerInputComponent(class UInputComponent* PlayerInputComponent) override;
cpp
加载资源
AMyPawn::AMyPawn()
{
static ConstructorHelpers::FObjectFinder<UInputMappingContext> ContextObj(TEXT("/Game/My/Input/IMC_MyTank.IMC_MyTank"));
if (ContextObj.Succeeded() && ContextObj.Object) { MappingContext = ContextObj.Object; }
static ConstructorHelpers::FObjectFinder<UInputAction> IA_Move(TEXT("/Game/My/Input/Actions/IA_Move.IA_Move"));
if (IA_Move.Succeeded() && IA_Move.Object) { MoveAction = IA_Move.Object; }
static ConstructorHelpers::FObjectFinder<UInputAction> IA_Look(TEXT("/Game/My/Input/Actions/IA_Look.IA_Look"));
if (IA_Move.Succeeded() && IA_Move.Object) { LookAction = IA_Look.Object; }
static ConstructorHelpers::FObjectFinder<UInputAction> IA_Interact(TEXT("/Game/My/Input/Actions/IA_Fire.IA_Fire"));
if (IA_Move.Succeeded() && IA_Move.Object) { FireAction = IA_Interact.Object; }
}
绑定
void AMyPawn::NotifyControllerChanged()
{
Super::NotifyControllerChanged();
// 绑定映射上下文
if (APlayerController* PlayerController = Cast<APlayerController>(Controller))
{
if (UEnhancedInputLocalPlayerSubsystem* Subsystem = ULocalPlayer::GetSubsystem<UEnhancedInputLocalPlayerSubsystem>(PlayerController->GetLocalPlayer()))
{
Subsystem->AddMappingContext(MappingContext, 0);
}
}
}
void AMyPawn::SetupPlayerInputComponent(UInputComponent* PlayerInputComponent)
{
Super::SetupPlayerInputComponent(PlayerInputComponent);
// 绑定动作映射与函数
if (UEnhancedInputComponent* EnhancedInputComponent = Cast<UEnhancedInputComponent>(PlayerInputComponent)) {
// Move
EnhancedInputComponent->BindAction(MoveAction, ETriggerEvent::Triggered, this, &AMy_Tank::Move_Forward);
// Fire
EnhancedInputComponent->BindAction(FireAction, ETriggerEvent::Started, this, &AMy_Tank::Action_Fire);
}
}
处理输入
void AMyPawn::Move_Forward(const FInputActionValue& Value)
{
FVector2D MovementVector = Value.Get<FVector2D>();//获取输入的值(两个)
float Distance = MovementVector.Y;//获取Y方向的值
const FRotator Rotation = Controller->GetControlRotation();//获取控制器的旋转
const FRotator YawRotation(0, Rotation.Yaw, 0);//只保留旋转的Yaw轴
FRotationMatrix RotMatrix(YawRotation);//创建旋转矩阵,描述旋转后的坐标轴
const FVector ForwardDirection = RotMatrix.GetUnitAxis(EAxis::Y);//获取新坐标轴的Y轴方向,即前方
AddMovementInput(ForwardDirection,Distance );//往ForwardDirection方向移动Distance
}
碰撞筛选
碰撞通道(TraceChannel)和碰撞查询参数(CollisionQueryParams)
一个是粗略筛选,一个是精细筛选
碰撞通道:
虚幻引擎预定义了多种碰撞通道,例如:ECC 是 Engine Collision Channel
| 枚举值 | 说明 |
|---|---|
ECC_WorldStatic | 静态物体(如地形、建筑)。 |
ECC_WorldDynamic | 动态物体(如可移动的物体)。 |
ECC_Pawn | 角色(玩家、NPC)。 |
ECC_Visibility | 用于可见性检测(如鼠标点击选中)。 |
ECC_Camera | 摄像机碰撞检测。 |
ECC_PhysicsBody | 启动物理的刚体。 |
ECC_Vehicle | 载具专用通道。 |
ECC_Destructible | 可破坏物体。 |
自定义碰撞通道
#define MyChannel ECC_GameTraceChannel1 //引擎提供了18个自定义的检测通道,这是1
碰撞查询参数:
碰撞通道筛选后才查看查询参数
FCollisionQueryParams 是 一个结构体,可以用其创建对象作为查询参数传入
FCollisionQueryParams Params;
Params.AddIgnoredActor(MyActor); // 忽略MyActor
Params.bTraceComplex = true; // 启用复杂碰撞
GetWorld()->LineTraceSingleByChannel(..., Params, ...);
FCollisionQueryParams 的核心成员
| 成员/方法 | 类型 | 说明 |
|---|---|---|
AddIgnoredActor() | void | 忽略特定Actor(不检测它)。 |
AddIgnoredComponent() | void | 忽略特定组件(如某个Mesh)。 |
bTraceComplex | bool | 是否启用复杂碰撞检测(精确到三角形级别,默认false)。 |
bReturnPhysicalMaterial | bool | 是否在FHitResult中返回物理材质(默认false)。 |
bDebugQuery | bool | 是否在调试视图中绘制检测射线(默认false)。 |
TraceTag | FName | 自定义标签(用于区分不同类型的检测)。 |
定时器(带lambda函数)
FTimerHandle TimerHandle;
GetWorld()->GetTimerManager().SetTimer(
TimerHandle,
[this]() // 捕获this指针
{
//在这里写代码,不要引用外部函数的对象,lambda函数运行时,外部对象早释放了
},
0.2f, // 延迟0.2秒
false // 一次性定时器
);

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



