ASC 挂在哪里:Actor 还是 PlayerState

这是 GAS 多人项目的第一个分水岭问题,答案直接影响断线重连后技能是否还在。

两种挂法的差别

挂在 Actor(角色) 挂在 PlayerState
角色死亡/重生 → ASC 随之销毁与重建 角色死亡/重生 → ASC 保留,状态不丢
实现简单,单体/角色不重生的游戏适合 断线重连、换角色、赛季制游戏必须
网络下 ASC 的 OwnerActor = 角色 OwnerActor = PlayerState,AvatarActor = 角色

选择规则: - 单机 / 不会重生 / 不断线重连 → 挂 Actor(简单直接); - 多人 + 会重生 / 会重连 / 换角色 → 挂 PlayerState。

Lyra 的做法(权威参考)

Epic 官方示例 Lyra 的 ALyraPlayerState 持有 ASC 和 AttributeSet,角色(ALyraCharacter)只是"Avatar(化身)"。角色死了,PlayerState 不动,技能与属性全部保留。这是多人项目的推荐做法。

C++ 侧关键代码:

// PlayerState 头文件
UPROPERTY(VisibleAnywhere, BlueprintReadOnly, Category="Abilities")
UAbilitySystemComponent* AbilitySystemComponent;
UPROPERTY()
UMyAttributeSet* AttributeSet;

// 并实现 IAbilitySystemInterface
UAbilitySystemComponent* GetAbilitySystemComponent() const override
{
    return AbilitySystemComponent;
}

三个配套概念

ASC 建立时需要配好三个"伙伴":

概念 作用 不配会怎样
OwnerActor ASC 的逻辑拥有者(权限判定) 权威/预测逻辑错乱
AvatarActor 视觉化身(地理位置、碰撞参考) 效果挂在看不见的地方
Replication Mode 属性同步给客户端的策略 网络带宽浪费或状态不同步

Replication Mode 三档

AbilitySystemComponent->SetReplicationMode(EGameplayEffectReplicationMode::Mixed);
模式 同步内容 适合
Full 所有 GE 与属性给所有人 竞技类(对手状态也要看)
Mixed 游戏性相关 GE 给所有人,UI 相关(如血条)只给自己 多数游戏的最佳选择
Minimal 几乎不同步 GE,只 tags/Cosmetic 省带宽(如大量小怪)

经验:主角用 Mixed,大量小怪用 Minimal。这是服务器带宽最直接的优化点之一。

初始化时机(第二个常见坑)

ASC 的初始化要在 OwnerActor 与 AvatarActor 都就绪后做:

void AMyPlayerState::BeginPlay()
{
    Super::BeginPlay();
    if (AbilitySystemComponent)
    {
        AbilitySystemComponent->InitAbilityActorInfo(this, GetPawn());  // Owner=this, Avatar=Pawn
    }
}

角色重生时也要重新调用 InitAbilityActorInfo(Avatar 变了),否则技能"锁在旧角色身上"。

本章小结

  • ASC 挂 Actor 还是 PlayerState:看是否需要"状态跨角色/跨重连保留",多人推荐 PlayerState。
  • 伙伴三概念:OwnerActor(权限)、AvatarActor(视觉)、Replication Mode(同步策略)。
  • 角色重生 / 断线重连后要重新 InitAbilityActorInfo。