Unreal Engine 高效数组复制用法详解

文章目录


前言

在 Unreal Engine 中,FFastArraySerializerFFastArraySerializerItem 是用于高效网络复制数组数据的工具类,尤其在需要频繁同步动态数组时(如背包系统、技能列表等场景)。以下通过一个 背包物品同步 的示例详细说明它们的用法。


提示:以下是本篇文章正文内容,下面案例可供参考

一、核心概念

  • FFastArraySerializerItem: 表示数组中的单个元素,需要包含复制标识符 ReplicationID 和 ReplicationKey。
  • FFastArraySerializer: 管理数组的容器类,负责处理网络复制逻辑和变化追踪。

二、实现步骤

2.1 定义 Item 结构体

cpp 复制代码
// 继承自 FFastArraySerializerItem
USTRUCT()
struct FInventoryItem : public FFastArraySerializerItem
{
    GENERATED_BODY()

    UPROPERTY()
    FName ItemID;       // 物品唯一ID

    UPROPERTY()
    int32 Quantity;     // 数量

    UPROPERTY()
    float Durability;   // 耐久度

    // 网络复制标识符(必须实现)
    void PreReplicatedRemove(const struct FInventoryArray& Serializer);
    void PostReplicatedAdd(const struct FInventoryArray& Serializer);
    void PostReplicatedChange(const struct FInventoryArray& Serializer);
};

2.2 定义数组容器

cpp 复制代码
// 继承自 FFastArraySerializer
USTRUCT()
struct FInventoryArray : public FFastArraySerializer
{
    GENERATED_BODY()

    UPROPERTY()
    TArray<FInventoryItem> Items;  // 物品数组

    // 必须重写:标识数组变化
    bool NetDeltaSerialize(FNetDeltaSerializeInfo& DeltaParms) override
    {
        return FFastArraySerializer::FastArrayDeltaSerialize<FInventoryItem, FInventoryArray>(Items, DeltaParms, *this);
    }

    // 示例方法:添加物品
    void AddItem(const FInventoryItem& NewItem)
    {
        Items.Add(NewItem);
        MarkItemDirty(Items.Last()); // 标记为脏数据以触发复制
    }

    // 示例方法:移除物品
    void RemoveItem(int32 Index)
    {
        if (Items.IsValidIndex(Index))
        {
            Items.RemoveAt(Index);
            MarkArrayDirty(); // 标记数组变化
        }
    }
};

2.3 在 Actor 或 Component 中使用

cpp 复制代码
UCLASS()
class AMyCharacter : public ACharacter
{
    GENERATED_BODY()

public:
    // 复制的背包数据
    UPROPERTY(Replicated)
    FInventoryArray Inventory;

    // 注册复制属性
    virtual void GetLifetimeReplicatedProps(TArray<FLifetimeProperty>& OutLifetimeProps) const override
    {
        Super::GetLifetimeReplicatedProps(OutLifetimeProps);
        DOREPLIFETIME(AMyCharacter, Inventory);
    }

    // 服务器端添加物品
    UFUNCTION(Server, Reliable)
    void Server_AddItem(FName ItemID, int32 Quantity);
    {
        FInventoryItem NewItem;
        NewItem.ItemID = ItemID;
        NewItem.Quantity = Quantity;
        NewItem.Durability = 100.f;
        Inventory.AddItem(NewItem);
    }
};

三、关键方法说明

3.1 MarkItemDirty()

  • 作用: 标记单个 Item 为"脏数据",触发网络复制。

  • 使用场景: 修改 Item 属性后调用,如:

cpp 复制代码
void ChangeItemQuantity(int32 Index, int32 NewQuantity)
{
    if (Inventory.Items.IsValidIndex(Index))
    {
        Inventory.Items[Index].Quantity = NewQuantity;
        Inventory.MarkItemDirty(Inventory.Items[Index]);
    }
}

3.2 MarkArrayDirty()

  • 作用: 标记整个数组变化(如添加/删除元素)。

  • 自动调用: 通过 AddItem() 或 RemoveItem() 间接调用。

四、回调函数处理

FInventoryItem 中实现复制回调,响应数据变化:

cpp 复制代码
void FInventoryItem::PostReplicatedAdd(const FInventoryArray& Serializer)
{
    // 客户端新增物品时触发(如更新UI)
    UMyUIWidget::Get()->RefreshInventory();
}

void FInventoryItem::PostReplicatedChange(const FInventoryArray& Serializer)
{
    // 客户端物品属性变化时触发(如更新数量显示)
    UMyUIWidget::Get()->UpdateItemDisplay(ItemID);
}

void FInventoryItem::PreReplicatedRemove(const FInventoryArray& Serializer)
{
    // 客户端移除物品前触发(如播放消失动画)
    UMyUIWidget::Get()->RemoveItemDisplay(ItemID);
}

五、网络复制流程

  1. 服务器修改数据 :调用 AddItem()RemoveItem() 或直接修改 Item 属性后标记脏数据。

  2. 引擎自动同步 :通过 NetDeltaSerialize 增量复制变化到客户端。

  3. 客户端触发回调 :根据操作类型(Add/Change/Remove)执行 PostReplicatedAdd 等函数。

六、注意事项

  • 仅在服务器修改数据 :客户端应通过 RPC(如 Server_AddItem)请求修改。

  • 避免频繁操作 :批量操作后调用一次 MarkArrayDirty() 减少带宽。

  • 自定义序列化 :如需优化,可重写 FInventoryItem::NetSerialize()

通过这种机制,FFastArraySerializer 能高效同步动态数组,适用于需要低延迟和高频率更新的游戏系统。

相关推荐
m0_552200825 小时前
《UE5_C++多人TPS完整教程》学习笔记49 ——《P50 应用瞄准偏移(Applying Aim Offset)》
c++·游戏·ue5
m0_552200825 小时前
《UE5_C++多人TPS完整教程》学习笔记50 ——《P51 多人游戏中的俯仰角(Pitch in Multiplayer)》
c++·游戏·ue5
CandyU25 小时前
UE5 基础应用 —— 09 - 展示类小项目
ue5
vonlycn5 小时前
UE5 性能优化(1) 模型合并,材质合并
ue5·材质
ue星空1 天前
月2期学习笔记
学习·游戏·ue5
郝学胜-神的一滴1 天前
基于OpenGL封装摄像机类:视图矩阵与透视矩阵的实现
c++·qt·线性代数·矩阵·游戏引擎·图形渲染
EQ-雪梨蛋花汤1 天前
【Unity笔记】Unity 编辑器扩展:打造一个可切换 Config.assets 的顶部菜单插件
unity·编辑器·游戏引擎
曼巴UE52 天前
UE5 制作游戏框架的部分经验积累(持续更新)
游戏·ue5
CandyU22 天前
UE5 基础应用 —— 10 - 控制台命令
ue5
极客柒2 天前
Unity 塔防自用可视化路点寻路编辑器
unity·编辑器·游戏引擎