UE创建ASC并开启网络复制

UE创建ASC并开启网络复制
一.创建ASC1.ASC创建位置对于单机游戏ASC创建在玩家状态(Player State)还是玩家角色(Player Character)里都是一样的但对于网络联机游戏ASC最好放在玩家状态(Player State)中。ASC绑在PlayerCharacter会导致AttributeSet/GE/Tag等都会随着PlayerCharacter的死亡而销毁。ASC 绑在PlayerState则不会由于PlayerCharacter的死亡销毁而销毁。新Character出生后通过 InitAbilityActorInfo找回 ASC并调用InitAbilityActorInfo重新绑定即可恢复全部原有数据。2.创建ASC设置复制模式#pragma once #include CoreMinimal.h #include GameFramework/PlayerState.h #include AbilitySystemComponent.h #include DemoPlayerStateBase.generated.h UCLASS() class DEMO_API ADemoPlayerStateBase : public APlayerState { GENERATED_BODY() public: ADemoPlayerStateBase(); protected: //创建ASC UPROPERTY(EditAnywhere, BlueprintReadWrite, Category ASC) UAbilitySystemComponent* ASC; };#include Cores/DemoPlayerStateBase.h ADemoPlayerStateBase::ADemoPlayerStateBase() { ASC CreateDefaultSubobjectUAbilitySystemComponent(TEXT(ASC)); if(ASC) { ASC-SetIsReplicated(true);//设置为可复制 ASC-SetReplicationMode(EGameplayEffectReplicationMode::Mixed);//设置模式为混合模式 } }复制模式适用场景特点Full单人游戏/小型多人全部客户端同步完整 GE 实例Buff 时长 / 层数 / 数值全同步网络开销大Mixed多人玩家角色自身本地客户端同步完整 GE其他玩家仅同步 GameplayTag、GameplayCue 视觉表现无完整 GE 数值MinimalNPC/观战单位所有客户端均不传输完整 GE仅同步 Tag 与 GC 特效带宽占用最低二.实现ASC组件接口1.接口介绍在面向对象编程中接口是一种特殊的抽象类型它定义了一组相关功能的行为协定但不包含任何实现。接口具备以下特征①纯粹的抽象接口只声明方法签名函数名、参数、返回值不提供任何方法体或成员变量。②协议性它规定了实现类“必须提供哪些功能”而不是“如何实现这些功能”。③解耦性接口将“做什么”与“怎么做”完全分离调用方只需知道接口协议无需了解实现类的具体类型。在Unreal Engine的C中接口是通过UINTERFACE宏声明的一个特殊的UObject子类。它本身不能被实例化其主要作用是① 为不同的AActor或UObject子类建立统一的通信契约。② 允许不相关的类共享相同的行为能力如IAbilitySystemInterface统一提供了获取UAbilitySystemComponent的访问点。UE官方对接口也做出了相应介绍具体可看官方文档Gameplay技能系统 - 配置的最佳实践 | Epic Developer Community2.实现 IAbilitySystemInterface 接口实现 IAbilitySystemInterface 接口就需要重写接口里的GetAbilitySystemComponent函数并且提供获取ASC的功能class DEMO_API ADemoPlayerStateBase : public APlayerState, public IAbilitySystemInterface { GENERATED_BODY() public: ADemoPlayerStateBase(); //IAbilitySystemInterface接口 virtual UAbilitySystemComponent* GetAbilitySystemComponent() const override;//实现IAbilitySystemInterface接口 UAbilitySystemComponent* ADemoPlayerStateBase::GetAbilitySystemComponent() const { return ASC; }三.ASC绑定Owner和Avatar绑定OwnerMixed复制模式才能正常生效ASC 知道数据该精准发给哪个客户端。绑定Avatar技能才能正确获取物理位置、播放动画GameplayCue找到作用目标。Owner通常指向PlayerStateAvatar指向PlayerCharacter。1.UE核心类的创建①游戏实例Game Instance最早创建生命周期最长通常跨关卡存在。负责存档、网络会话、全局 UI、玩家登录数据等特点不随关卡切换销毁除非退出游戏类比整个游戏的“总管理器”②游戏模式Game Mode关卡加载后由 Game Instance 驱动创建。负责规则、胜负、刷怪、玩家重生、选 Pawn 类型等特点只在服务端存在单机时本地就是服务端类比这一局的“裁判 关卡导演”③ 游戏状态Game StateGame Mode 创建后用来表示整局游戏的全局状态。负责比分、剩余时间、队伍信息等特点会复制到所有客户端大家看到同一份“局内数据”类比记分牌、比赛信息板④玩家控制器Player Controller玩家加入后由 Game Mode 创建。负责输入、相机、UI、Possess Pawn特点先创建是玩家在本地的“操作中枢”类比手柄/键鼠背后的“操作员”⑤玩家状态Player State在 Player Controller 初始化阶段创建并绑定到 Controller。负责玩家名、分数、队伍、存活状态等跟玩家绑定、跨 Pawn 存活的数据特点后于 Controller 创建但通常比 Pawn 活得更久类比玩家档案/战绩卡⑥玩家角色Player Character最后才生成并交给 Controller 控制。负责移动、动画、碰撞、具体玩法表现特点可被销毁、重生、替换Controller 和 State 一般还在类比场上实际操作的“角色实体”2.InitAbilityActorInfo函数InitAbilityActorInfo 是AbilitySystemComponent最核心的初始化函数。它的作用就一个正式建立 ASC 与它的“逻辑主人”和“物理身体”之间的绑定关系。调用InitAbilityActorInfo函数建立引用ASC 内部保存了OwnerActor和AvatarActor的指针。之后技能系统通过 ASC 就能随时知道“谁拥有这个 ASC”和“这个 ASC 代表哪个身体”。激活网络复制ASC 知道了 OwnerMixed复制模式才能正式生效——知道数据该发给哪个客户端。技能可以激活GameplayAbility 需要从 Avatar 获取位置、朝向从 Owner 获取权限。调用这个函数后这些信息才完整。GameplayEffect 可以正确应用GE 应用时需要知道“修改谁的属性”通过 Owner 找到属性集、“效果作用在谁身上”通过 Avatar 获取物理目标。触发OnAvatarSet事件你可以在蓝图中监听这个事件用来在角色出生时给予初始技能。3.绑定位置在PlayerState创建后PlayerCharacter还未创建此时无法获取PlayerCharacter相关数据即无法绑定Avatar。所以选择在PlayerCharacter中进行绑定。同理BeginPlay执行时客户端上的PlayerState可能还未同步服务器端 Controller 与 Pawn 的关联也可能尚未完全建立导致 Owner 或 Avatar 为空。PossessedBy和OnRep_PlayerState是三者Controller、PlayerState、Character都就绪的最早安全时机。在 Unreal Engine 的 GAS 框架中调用InitAbilityActorInfo来绑定 Owner 和 Avatar 的标准位置有两个分别针对服务器和客户端。PossessedBy服务器端执行位置服务器触发时机当PlayerController接管Character的控制权时通常由RestartPlayer触发。OnRep_PlayerState客户端执行位置客户端触发时机当客户端的Character收到服务器同步过来的PlayerState时。public: //Possed By,服务端绑定 virtual void PossessedBy(AController* NewController) override; //OnRep PlayerState客户端绑定 virtual void OnRep_PlayerState() override;// Possed By void ADemoCharacterBase::PossessedBy(AController* NewController) { Super::PossessedBy(NewController); InitAbilityActorInfo(); } //OnRep PlayerState void ADemoCharacterBase::OnRep_PlayerState() { Super::OnRep_PlayerState(); InitAbilityActorInfo(); }//InitAbilityActorInfo void ADemoCharacterBase::InitAbilityActorInfo() { if(ADemoPlayerStateBase * DemoState GetPlayerStateADemoPlayerStateBase()) DemoState-GetAbilitySystemComponent()-InitAbilityActorInfo(DemoState, this); }