UC++

垃圾引擎,毁我青春,垃圾C++,毁我未来



前言

垃圾引擎,毁我青春,垃圾C++,毁我未来
满腔的怒火使我开悟,写给自己看的博客,最后会附我的项目,基本纯C++实现,基本无蓝图内容,部分内容经AI整理,已经过个人校对,放心食用

学习路径:
C++→UE核心类概览与生命周期→灵活使用反射系统→UC++基本语法→UC++基础数据结构→常用类方法→虚幻网络部分(浅尝辄止)→失业→恭喜可以随便搓游戏了


tip:使用前关闭虚幻自带热重载(实时编译)

引擎右下角的小魔方按钮的√给它关了,能免去莫名其妙的BUG调试时间

二、UE核心类概览-必看!!!

核心游戏类
🎯 Pawn/Character - 玩家/AI控制的实体(可移动的角色)
📊 PlayerState - 玩家数据(分数、姓名、等级)- 跨关卡保持
🎮 HUD/UMG - 用户界面显示
🤖 AIController - AI控制器
🤖PlayerController -玩家控制器
🌍 Level/Map - 关卡本身
📦 Actor - 所有对象的老祖宗(Pawn/HUD等都继承自它)
组件系统
🔧 SceneComponent - 有位置的组件(Transform)
🎨 PrimitiveComponent - 可视/可碰撞组件(Mesh、碰撞盒)
🎯 CameraComponent - 摄像机组件
🔫 SkeletalMeshComponent - 骨骼网格组件
⚡ ParticleSystemComponent - 粒子特效组件
数据和资源类
💾 SaveGame - 存档数据基类
📋 DataTable - 数据表格(Excel式数据)
🎨 Material - 材质
🔊 SoundBase - 音效基类
📁 DataAsset - 纯数据资产
网络和同步类
🌐 OnlineSession - 在线会话管理
👥 PlayerState - 网络同步的玩家数据
📡 Replication - 属性同步系统
🔐 Authority - 服务器权威控制
常用工具类
⏰ TimerManager - 定时器管理
📝 GameplayStatics - 静态工具函数大全
🔍 Cast - 类型转换
📢 Delegate/Broadcast - 事件系统
🗃️ TArray/TMap - 容器类

基本生命周期:

创建顺序:

游戏启动 → GameInstance → 关卡 → World → GameMode → 玩家加入 → PlayerController

销毁顺序:

玩家离开 → PlayerController → 卸载关卡 → GameMode → World → 游戏关闭 → GameInstance

重点:
GameInstance跟着游戏同生死;GameMode跟关卡,切换就重建;PlayerController 最短暂,随玩家进出创建与析构,后面还会因为虚幻网络部分的C/S架构 + 属性复制 + RPC,会继续聊到这个

游戏实例GameInstance的作用

🎮 游戏流程控制​ - 管理整个游戏会话的状态机
💾 跨关卡数据持久化​ - 唯一能在关卡间保持数据的对象 非常重要!!
🔧 全局系统管理​ - 所有子系统的容器和协调者 子系统后面会涉及到
🌐 网络和社交​ - 在线功能、多人游戏、好友系统
⚙️ 配置管理​ - 图形、音频、输入等全局设置
📊 数据分析​ - 性能监控、用户行为追踪
🏪 资源管控​ - 全局资源加载、内存管理
📱 平台适配​ - 不同平台的特定功能处理
🚨 错误处理​ - 崩溃报告、用户反馈
🔄 关卡协调​ - 虽然涉及关卡加载,但主要是协调作用

游戏实例怎么用-Gameinstance -2025/11/28更新

游戏实例示例代码

游戏实例中可以存一些经常要用的变量,比如分数,当前全局玩家数量之类的,然后由Gamemode,玩家控制器拿出来用

// SimpleGameInstance.h
#pragma once

#include "CoreMinimal.h"
#include "Engine/GameInstance.h"
#include "SimpleGameInstance.generated.h"

UCLASS()
class YOURGAME_API USimpleGameInstance : public UGameInstance
{
    GENERATED_BODY()

public:
    // 储存一个简单的分数
    UPROPERTY(BlueprintReadWrite, Category = "Simple")
    int32 Score = 0;

    // 储存玩家名字
    UPROPERTY(BlueprintReadWrite, Category = "Simple") 
    FString PlayerName = "Player";

    // 增加分数的函数
    UFUNCTION(BlueprintCallable, Category = "Simple")
    void AddScore(int32 Points)
    {
        Score += Points;
        UE_LOG(LogTemp, Warning, TEXT("分数增加 %d,现在是 %d"), Points, Score);
    }

    // 重置分数
    UFUNCTION(BlueprintCallable, Category = "Simple")
    void ResetScore()
    {
        Score = 0;
        UE_LOG(LogTemp, Warning, TEXT("分数重置为 0"));
    }
};

在角色类中获取游戏实例中的数据来使用,游戏实例中的数据只要游戏没结束一直都会保留!

PlayerController、PlayerState、Pawn等玩家相关类中,可以直接获取和使用GameInstance,这里仅仅做个简单示例

// SimpleCharacter.cpp
#include "SimpleGameInstance.h"
#include "Kismet/GameplayStatics.h"

void ASimpleCharacter::AddSomeScore()
{
    // 获取GameInstance
    UGameInstance* GameInstance = GetGameInstance();
    if (GameInstance)
    {
        // 转换成我们的GameInstance
        USimpleGameInstance* MyGameInstance = Cast<USimpleGameInstance>(GameInstance);
        if (MyGameInstance)
        {
          
            MyGameInstance->AddScore(10);
            MyGameInstance->PlayerName = "Hero";
            
            UE_LOG(LogTemp, Warning, TEXT("玩家名字: %s"), *MyGameInstance->PlayerName);
        }
    }
}

void ASimpleCharacter::OnDeath()
{
    // 死亡时重置分数
    USimpleGameInstance* MyGameInstance = Cast<USimpleGameInstance>(GetGameInstance());
    if (MyGameInstance)
    {
        MyGameInstance->ResetScore();
    }
}

注意:虚幻引擎有着自己的规则,不要试图抵抗它,遵循官方命名规则和推荐写法能最大化效率开发,除非您已经掌握修改引擎底层的能力


虚幻反射系统 2025/11/30更新

反射系统是指在运行时或编译时,程序能够自省自身的结构——比如类有哪些属性、方法、父类是谁等信息(自己查看自己的信息),C++ 本身并不原生支持反射,但虚幻通过一套自定义机制实现了这个功能。

虚幻的反射系统基于宏标记代码 + 代码生成工具(Unreal Header Tool,简称 UHT)协同工作.
作为Gamepaly游戏程序,绝大多数人不需要掌握它的底层实现.专注与怎么用就好了.

反射系统的组成

宏标记

使用 UCLASS(), UPROPERTY(), UFUNCTION()等宏标注类、属性、函数等,使 UHT 能解析它们。

Unreal Header Tool(UHT)

构建过程中运行的工具,扫描头文件,根据宏生成对应的 .generated.h文件和反射代码。

Generated Code(反射代码)

所有标记为反射类型的对象,都会生成一个对应的 YourClass.generated.h文件,其中包含注册信息供运行时使用。

运行时反射支持

虚幻通过 UObject, FProperty, UFunction等类提供运行时的访问能力。
下面直接看示例,其类似于初学CPP时的helloworld

// MyActor.h
#pragma once

#include "CoreMinimal.h"
#include "GameFramework/Actor.h"
#include "MyActor.generated.h"  // 必须包含这个

UCLASS()
class MYGAME_API AMyActor : public AActor
{
    GENERATED_BODY()

public:
    // 构造函数
    AMyActor();

protected:
    // 可被序列化和在编辑器中显示的属性
    UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "MyCategory")
    float Health;

    // 可在蓝图中调用的函数
    UFUNCTION(BlueprintCallable, Category = "MyFunctions")
    void TakeDamage(float DamageAmount);
};

我现在先粗浅的概况这些宏的使用方法

1:所有虚幻生成的类,上方必须被添加UCLASS()宏标记,这样编辑器才能将类正确反射到编辑器并开启资源回收
2.所有变量,上方必须添加 UPROPERTY()宏标记,这样编辑器才能将变量正确反射到编辑器
3.所有函数,上方必须添加UFUNCTION()宏标记,这样编辑器才能将变量正确反射到编辑器

4: 所有类内部必须添加GENERATED_BODY()宏标记,这样编辑器才能将类正确反射到编辑器
5:所有 UCLASS()、UPROPERTY()、UFUNCTION()都必须写在头文件中(别问为什么,UHT无法解析CPP文件,按EPIC的来)
6:每个反射类都需要一个对应的 .generated.h,名称就是你创键的类名+.generated.h,且必须被 #include在头文件的末尾

UPROPERTY()宏

UPROPERTY用于标记类的成员变量,使其支持以下功能:
编辑器显示和修改(EditAnywhere / VisibleAnywhere)
蓝图读写(BlueprintReadWrite / BlueprintReadOnly)
网络复制(Replicated)
序列化(SaveGame)
GC 引用追踪(防止被错误回收)

括号里的常见参数代表的含义:
EditAnywhere / VisibleAnywhere 在编辑器中是否可编辑/可见
BlueprintReadWrite / ReadOnly 蓝图是否可读写
Category 在编辑器中的分类标签(会在编辑器中给一块分类便于你管理变量或者资源)
Replicated 启用网络同步
SaveGame 可序列化到存档
Transient 不保存、不复制

//此变量编辑器任意地方可编辑,蓝图可读写,分类是Stats,网络同步开启
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category="Stats", Replicated)
int32 Score;

UFUNCTION()宏

UFUNCTION用于标记方法,使其能被蓝图调用、网络 RPC、委托绑定等。
至于其它宏参数,大家可去官方文档自行查阅用法

UFUNCTION(BlueprintCallable, Category="Combat")
void FireWeapon();

UFUNCTION(Server, Reliable)
void ServerFire(); // 网络RPC:服务器执行

UFUNCTION(Client, Unreliable)
void ClientShowHitEffect(); // 网络RPC:客户端执行

虚幻枚举、结构体也支持反射

枚举:

UENUM(BlueprintType)
enum class EWeaponState : uint8
{
    Idle,
    Firing,
    Reloading
};

结构体:

USTRUCT(BlueprintType)
struct FMyStruct
{
    GENERATED_BODY()

    UPROPERTY(EditAnywhere, BlueprintReadWrite)
    FString Name;

    UPROPERTY(EditAnywhere)
    int32 Level;
};

运行时代码中使用反射

你可以通过反射接口在运行时动态访问类、属性或函数:
示例:查找并设置属性值

UMyActor* Actor = ...;
UClass* Class = Actor->GetClass();

// 查找属性
FProperty* Property = Class->FindPropertyByName(TEXT("Health"));
if (FFloatProperty* FloatProp = CastField<FFloatProperty>(Property))
{
    float CurrentHealth = FloatProp->GetPropertyValue_InContainer(Actor);
    FloatProp->SetPropertyValue_InContainer(Actor, CurrentHealth - 10.0f);
//代码意思是,从类中取出变量并重新设置变量的值
}

反射示例:调用函数

UFunction* Func = Actor->FindFunction(FName("TakeDamage"));//通过名称查找函数
if (Func)
{
    struct { float DamageAmount; } Params;
    Params.DamageAmount = 25.0f;
    
    Actor->ProcessEvent(Func, &Params);//在 Actor对象上调用名为 Func的函数,并传入参数 Params。取决于你调用函数的参数,如果参数传错了会崩溃
    }

警告!仅展示引擎内部反射机制,此写法类型不安全,性能差,可读性差,实际工程不要这么写,而是直接调用对象即可

好的,同时你现在已经学会虚幻枚举和结构体的用法了,那么现在还有一些其它基本数据结构,用法和CPP基本一致

虚幻的基本数据结构对比标准 C++,帮助你快速理解它们的异同和使用场景。

一、字符串类型

// C++标准类型
std::string Str = "Hello";
std::string Full = Str + " World";

// UE UE 使用 TEXT("...")宏包裹字符串,确保跨平台(Unicode)兼容。
//FText是唯一支持本地化的字符串类型,UI 必须用 FText。
FString Str = TEXT("Hello");
FString Full = Str + TEXT(" World");
FString Formatted = FString::Printf(TEXT("分数: %d"), 100);
----------------------------------------------------------------------------------------
//基本用法
#include "Misc/Paths.h"
#include "Internationalization/Text.h"

void StringExamples() {
    // === FString: 可变字符串,最常用 ===
    FString Str1 = TEXT("Hello Unreal");           // 字面量初始化
    FString Str2 = FString::Printf(TEXT("Score: %d"), 100); // 格式化
    FString Str3 = Str1 + TEXT(" World");         // 拼接
    int32 Len = Str1.Len();                       // 长度
    bool IsEmpty = Str1.IsEmpty();                // 判空
    FString ToUpper = Str1.ToUpper();             // 转大写
    
    // === FName: 不可变标识符,用于资源引用 ===
    FName Name1 = TEXT("PlayerController");       // 创建名称
    FName Name2 = FName(TEXT("PlayerController")); // 另一种创建方式
    // Name1 = TEXT("NewName");  // 错误!FName不可修改
    bool SameName = (Name1 == TEXT("PlayerController")); // 比较
    
    // === FText: 本地化文本,支持多语言 ===
    FText Text1 = FText::FromString(TEXT("Hello")); // 从字符串创建
    FText Text2 = NSLOCTEXT("Namespace", "Key", "Localized Text"); // 本地化
    FText Text3 = FText::AsCultureInvariant(TEXT("Invariant")); // 文化无关
    
    // === 字符串转换 ===
    FString StringFromName = Name1.ToString();    // FName → FString
    FString StringFromText = Text1.ToString();    // FText → FString
    FName NameFromString = FName(*Str1);          // FString → FName
    // FText不能直接从FString转换,需要指定上下文
}

二、标识符

//FName是给编辑器查找用的。FString→ FName有转换开销,尽量缓存复用
FName playername = TEXT("name");

三、容器类

虚幻引擎中的容器使用和STL基本一致,右边的是虚幻容器类,bro,不要说你不知道STL里都是些啥
Vector 与TArray

#include <vector>
#include <iostream>
#include <algorithm>

void VectorExample() {
    // === 创建和添加 ===
    std::vector<int> Numbers;
    Numbers.reserve(10);           // 预分配内存
    Numbers.push_back(1);          // 尾部添加
    Numbers.push_back(2);
    Numbers.insert(Numbers.begin() + 1, 99); // 中间插入
    
    // === 访问和查询 ===
    int First = Numbers[0];        // 下标访问
    int Second = Numbers.at(1);    // 安全访问(会抛异常)
    int Size = Numbers.size();     // 元素个数
    bool Empty = Numbers.empty();  // 是否为空
    
    // === 修改 ===
    Numbers[0] = 100;              // 直接修改
    std::sort(Numbers.begin(), Numbers.end()); // 排序
    
    // === 删除 ===
    Numbers.pop_back();            // 删除尾部
    Numbers.erase(Numbers.begin()); // 删除指定位置
    Numbers.clear();               // 清空所有
    
    // === 遍历 ===
    for(int Num : Numbers) {       // 范围for循环
        std::cout << Num << " ";
    }
}


-------------------------------------------
#include "Containers/Array.h"

void TArrayExample() {
    // === 创建和添加 ===
    TArray<int32> Numbers;
    Numbers.Reserve(10);           // 预分配内存  
    Numbers.Add(1);                // 尾部添加
    Numbers.Add(2);
    Numbers.Insert(99, 1);         // 在索引1处插入
    
    // === 访问和查询 ===
    int32 First = Numbers[0];       // 下标访问
    int32 Second = Numbers[1];     // 直接访问(越界崩溃)
    int32 Size = Numbers.Num();     // 元素个数
    bool Empty = Numbers.IsEmpty(); // 是否为空
    
    // === 修改 ===
    Numbers[0] = 100;              // 直接修改
    Numbers.Sort();                // 排序(默认升序)
    
    // === 删除 ===
    Numbers.Pop();                 // 删除尾部
    Numbers.RemoveAt(0);           // 删除指定位置
    Numbers.Empty();               // 清空所有
    
    // === 遍历 ===
    for(int32 Num : Numbers) {      // 范围for循环
        UE_LOG(LogTemp, Log, TEXT("%d"), Num);
    }
}

Map 与TMap

#include <map>
#include <string>

void MapExample() {
    // === 创建和添加 ===
    std::map<std::string, int> PlayerScores;
    PlayerScores["Alice"] = 100;    // 直接赋值添加
    PlayerScores.insert({"Bob", 85}); // insert方法添加
    PlayerScores.emplace("Charlie", 92); // 原地构造
    
    // === 访问和查询 ===
    int AliceScore = PlayerScores["Alice"]; // 下标访问(不存在会创建)
    int BobScore = PlayerScores.at("Bob");  // 安全访问(不存在抛异常)
    bool HasAlice = PlayerScores.count("Alice") > 0; // 是否存在
 
    
    // === 修改 ===
    PlayerScores["Alice"] = 150;    // 修改值
    
    // === 删除 ===
    PlayerScores.erase("Bob");      // 按键删除
    PlayerScores.clear();           // 清空所有
    
    // === 遍历 ===
    for(const auto& Pair : PlayerScores) {
        std::cout << Pair.first << ": " << Pair.second << std::endl;
    }
}

--------------------------------------------------------------------------
#include "Containers/Map.h"

void TMapExample() {
    // === 创建和添加 ===
    TMap<FString, int32> PlayerScores;
    PlayerScores.Add("Alice", 100);     // Add方法添加
    PlayerScores.Add("Bob", 85);
    PlayerScores.Emplace("Charlie", 92); // Emplace原地构造
    
    // === 访问和查询 ===
    int32 AliceScore = PlayerScores["Alice"]; // 下标访问(不存在会创建!)
    int32 BobScore;
    bool FoundBob = PlayerScores.TryGetValue("Bob", BobScore); // 安全获取
    bool HasAlice = PlayerScores.Contains("Alice"); // 是否存在
    int32 Index = PlayerScores.Find("Alice");      // 查找索引
    
    // === 修改 ===
    PlayerScores["Alice"] = 150;      // 修改值
    
    // === 删除 ===
    PlayerScores.Remove("Bob");        // 按键删除
    PlayerScores.Empty();              // 清空所有
    
    // === 遍历 ===
    for(const auto& Pair : PlayerScores) {
        UE_LOG(LogTemp, Log, TEXT("%s: %d"), *Pair.Key, Pair.Value);
    }
}

Set 与TSet

#include <set>
#include <string>

void SetExample() {
    // === 创建和添加 ===
    std::set<std::string> UniqueNames;
    UniqueNames.insert("Alice");     // 插入元素
    UniqueNames.insert("Bob");
    UniqueNames.insert("Alice");     // 重复插入无效
    
    // === 访问和查询 ===
    bool HasAlice = UniqueNames.count("Alice") > 0; // 是否存在
    auto It = UniqueNames.find("Bob"); // 查找迭代器
    
    // === 删除 ===
    UniqueNames.erase("Alice");       // 按键删除
    UniqueNames.clear();              // 清空所有
    
    // === 遍历 ===
    for(const std::string& Name : UniqueNames) {
        std::cout << Name << std::endl;
    }
}

------------------------------------------------------------
#include "Containers/Set.h"

void TSetExample() {
    // === 创建和添加 ===
    TSet<FString> UniqueNames;
    UniqueNames.Add("Alice");         // 添加元素
    UniqueNames.Add("Bob");
    bool Added = UniqueNames.Add("Alice"); // 重复添加返回false
    
    // === 访问和查询 ===
    bool HasAlice = UniqueNames.Contains("Alice"); // 是否存在
    bool Found = UniqueNames.Contains("Alice");
    
    // === 删除 ===
    UniqueNames.Remove("Alice");      // 按键删除
    UniqueNames.Empty();              // 清空所有
    
    // === 遍历 ===
    for(const FString& Name : UniqueNames) {
        UE_LOG(LogTemp, Log, TEXT("%s"), *Name);
    }
}

Queue 与 TQueue

#include <queue>
#include <string>

void QueueExample() {
    // === 创建和入队 ===
    std::queue<std::string> MessageQueue;
    MessageQueue.push("First");      // 入队
    MessageQueue.push("Second");
    
    // === 访问和查询 ===
    std::string FrontMsg = MessageQueue.front(); // 查看队首
    std::string BackMsg = MessageQueue.back();   // 查看队尾
    bool Empty = MessageQueue.empty(); // 是否为空
    size_t Size = MessageQueue.size(); // 元素个数
    
    // === 出队 ===
    MessageQueue.pop();              // 出队(删除队首)
    
    // === 注意:没有直接遍历方法,需要逐个pop ===
    while(!MessageQueue.empty()) {
        std::string Msg = MessageQueue.front();
        MessageQueue.pop();
        std::cout << Msg << std::endl;
    }
}

-----------------------------------------------------------
#include "Containers/Queue.h"

void TQueueExample() {
    // === 创建和入队 ===
    TQueue<FString> MessageQueue;
    MessageQueue.Enqueue("First");   // 入队
    MessageQueue.Enqueue("Second");
    
    // === 访问和查询 ===
    FString FrontMsg;
    MessageQueue.Peek(FrontMsg);     // 查看队首(不删除)
    bool Empty = MessageQueue.IsEmpty(); // 是否为空
    
    // === 出队 ===
    FString OutMsg;
    MessageQueue.Dequeue(OutMsg);    // 出队(获取并删除队首)
    
    // === 批量处理 ===
    while(MessageQueue.Dequeue(OutMsg)) {
        UE_LOG(LogTemp, Log, TEXT("%s"), *OutMsg);
    }
}

基础数值类型

// C++ 原生类型
void NativeTypes() {
    int a = 10;           // 32位有符号整数
    float b = 3.14f;      // 32位浮点数
    double c = 3.14159;   // 64位浮点数
    bool d = true;        // 布尔值
    char e = 'A';         // 字符
}

// UE 封装类型
void UETypes() {
    int32 a = 10;         // 明确32位有符号整数
    int64 b = 10000000000; // 64位有符号整数
    float c = 3.14f;      // 32位浮点数(与C++相同)
    double d = 3.14159;   // 64位浮点数(与C++相同)
    bool e = true;        // 布尔值(与C++相同)
    uint32 f = 100;       // 无符号32位整数
    uint8 g = 255;        // 无符号8位整数(0-255)
}

向量和数学类型(最常用的,一定得弄清楚)

#include "Math/Vector.h"
#include "Math/Rotator.h"
#include "Math/Transform.h"

void MathTypes() {
    // === FVector: 三维向量(x,y,z) ===
    FVector Pos1 = FVector(1.0f, 2.0f, 3.0f);           // 构造函数
    FVector Pos2 = FVector::ZeroVector;                 // 零向量
    FVector Pos3 = FVector::ForwardVector;              // 前向量(1,0,0)
    FVector Pos4 = FVector(10.0f, 0.0f, 0.0f);         // X轴方向
    
    float Length = Pos1.Size();                        // 向量长度
    FVector Normalized = Pos1.GetSafeNormal();         // 单位向量
    FVector Added = Pos1 + Pos2;                       // 向量加法
    FVector Scaled = Pos1 * 2.0f;                      // 数乘
    
    // === FRotator: 欧拉角旋转(pitch,yaw,roll) ===
    FRotator Rot1 = FRotator(45.0f, 90.0f, 0.0f);       // 俯仰、偏航、翻滚  这玩意不懂的可以百度或者问AI,是游戏开发基本知识
    FRotator Rot2 = FRotator::ZeroRotator;             // 零旋转
    FRotator FromVector = FRotationMatrix::MakeFromZ(FVector::UpVector).Rotator();
    
    // === FQuat: 四元数,避免万向节死锁 ===           //万向节死锁
    FQuat Quat1 = FQuat(FRotator(45.0f, 90.0f, 0.0f)); // 从旋转创建
    FQuat Quat2 = FQuat::Identity;                     // 单位四元数
    
    // === FTransform: 变换矩阵(位置+旋转+缩放) ===
    FTransform Transform1;                             // 默认构造
    FTransform Transform2 = FTransform(Rot1, Pos1);    // 位置和旋转
    FTransform Transform3 = FTransform::Identity;       // 单位变换
    
    FVector NewPos = Transform1.GetLocation();         // 获取位置
    FRotator NewRot = Transform1.Rotator();            // 获取旋转
}

颜色相关类型与常用方法

#include "Math/Color.h"
void ColorTypes() {
    // === FColor: 8位RGBA颜色(0-255) ===
    FColor Color1 = FColor(255, 128, 0, 255);         // RGBA构造
    FColor Color2 = FColor::Red;                       // 预定义颜色
    FColor Color3 = FColor::White;
    FColor Color4 = FColor(255, 255, 255);            // RGB自动设Alpha=255
    
    // === FLinearColor: 浮点RGBA颜色(0.0-1.0) ===
    FLinearColor LinearColor1 = FLinearColor(1.0f, 0.5f, 0.0f, 1.0f);
    FLinearColor LinearColor2 = FLinearColor::Blue;
    FLinearColor LinearColor3 = FLinearColor(Color1); // FColor → FLinearColor
    
    // === 颜色转换 ===
    FColor ConvertedBack = LinearColor1.ToFColor(true); // 带伽马校正
    FLinearColor GammaCorrected = Color1.ReinterpretAsLinear(); // 重新解释
}

时间和日期类型与常用方法

#include "HAL/PlatformTime.h"
#include "Misc/DateTime.h"

void TimeTypes() {
    // === FDateTime: 日期时间 ===
    FDateTime Now = FDateTime::Now();                   // 当前时间
    FDateTime Today = FDateTime::Today();               // 今天零点
    FDateTime Specific = FDateTime(2024, 12, 25, 10, 30, 0); // 指定时间
    
    int32 Year = Now.GetYear();                        // 年
    int32 Month = Now.GetMonth();                      // 月
    int32 Day = Now.GetDay();                          // 日
    int32 Hour = Now.GetHour();                        // 时
    FString IsoDate = Now.ToIso8601();                 // ISO格式字符串
    
    // === FTimespan: 时间间隔 ===
    FTimespan Span1 = FTimespan(1, 30, 0);             // 1小时30分钟
    FTimespan Span2 = Now - Today;                     // 时间差
    double TotalHours = Span2.GetTotalHours();         // 总小时数
    
    // === 计时相关 ===
    double StartTime = FPlatformTime::Seconds();       // 高精度计时开始
    // ... 执行一些操作 ...
    double EndTime = FPlatformTime::Seconds();         // 计时结束
    double Elapsed = EndTime - StartTime;              // 耗时(秒)
}

路径和文件类型与常用方法

#include "Misc/Paths.h"
#include "GenericPlatform/GenericPlatformFile.h"

void PathTypes() {
    // === 文件路径操作 ===
    FString TestPath = TEXT("C:\\Project\\Content\\..\\Content\\Texture.uasset");
   FString CleanPath = FPaths::CleanPath(TestPath);           // 清理路径
    FString AbsolutePath = FPaths::ConvertRelativePathToFull(TestPath); // 转绝对路径
    FString BaseName = FPaths::GetBaseFilename(TestPath);      // 获取文件名(无扩展名)
    FString Extension = FPaths::GetExtension(TestPath);         // 获取扩展名
    FString PathPart = FPaths::GetPath(TestPath);              // 获取路径部分
    
    // === 引擎特殊路径 ===
    FString ProjectDir = FPaths::ProjectDir();              // 项目目录
    FString ContentDir = FPaths::ProjectContentDir();       // Content目录
    FString EngineDir = FPaths::EngineDir();                // 引擎目录
    FString SaveDir = FPaths::ProjectSavedDir();            // 保存目录
    FString ScreenShotDir = FPaths::ScreenShotDir();     // 截图目录
    
  
}
}
Logo

有“AI”的1024 = 2048,欢迎大家加入2048 AI社区

更多推荐