目标:使用GAS制作武器,并赋予能力
流程:

Gameplay AbilitySystem

1.启用插件:GameplayAbilities

2.创建类



3.尝试编译,遇到报错,原因是在Source/Warrior/Warrior.Build.cs里缺少GameplayTasks模块依赖
// Copyright Epic Games, Inc. All Rights Reserved.
using UnrealBuildTool;
public class Warrior : ModuleRules
{
public Warrior(ReadOnlyTargetRules Target) : base(Target)
{
PCHUsage = PCHUsageMode.UseExplicitOrSharedPCHs;
PublicDependencyModuleNames.AddRange(new string[]
{
"Core",
"CoreUObject",
"Engine",
"InputCore",
"EnhancedInput",
"GameplayTags",
"GameplayTasks"
});
PrivateDependencyModuleNames.AddRange(new string[] { });
// 如果您使用的是Slate UI,请取消注释
// PrivateDependencyModuleNames.AddRange(new string[] { "Slate", "SlateCore" });
// 如果您正在使用在线功能,请取消注释
// PrivateDependencyModuleNames.Add("OnlineSubsystem");
// To include OnlineSubsystemSteam, add it to the plugins section in your uproject file with the Enabled attribute set to true
}
}
再编译,成功!
4.在角色基类里,添加能力系统组件和属性集:
protected:
#pragma region AbilitySystem
//能力系统组件
UPROPERTY(VisibleAnywhere, BlueprintReadOnly, Category = "AbilitySystem")
UWarriorAbilitySystemComponent* WarriorAbilitySystemComponent;
// 属性集
UPROPERTY(VisibleAnywhere, BlueprintReadOnly, Category = "AbilitySystem")
UWarriorAttributeSet* WarriorAttributeSet;
#pragma endregion
创建他们的getter函数:
public:
#pragma region getter
FORCEINLINE UWarriorAbilitySystemComponent* GetWarriorAbilitySystemComponent() const { return WarriorAbilitySystemComponent; }
FORCEINLINE UWarriorAttributeSet* GetWarriorAttribute() const { return WarriorAttributeSet; }
#pragma endregion
这段代码展示了C++中使用#pragma region指令来组织getter方法的典型用法。主要特点包括:
-
#pragma region getter和#pragma endregion这对指令用于将相关代码折叠为一个可命名的逻辑区域,方便在IDE中管理代码结构。 -
两个getter方法都使用了
FORCEINLINE宏,这通常表示编译器会强制内联这些简单的方法调用以提高性能。 -
方法返回的是指向组件对象的指针:
GetWarriorAbilitySystemComponent()返回UWarriorAbilitySystemComponent类型指针GetWarriorAttribute()返回UWarriorAttributeSet类型指针
-
两个方法都被声明为
const,表示它们不会修改类的成员变量。
5.在构造函数里构造这两个组件:
// 构造函数
AWarriorBaseCharacter::AWarriorBaseCharacter()
{
// 将此字符设置为每帧调用Tick()。如果你不需要它,你可以关闭它来提高性能。
PrimaryActorTick.bCanEverTick = false;
PrimaryActorTick.bStartWithTickEnabled = false;
/** 图元是否接收贴花。 */
GetMesh()->bReceivesDecals = false;
//将能力系统组件添加到角色
WarriorAbilitySystemComponent = CreateDefaultSubobject<UWarriorAbilitySystemComponent>(TEXT("WarriorAbilitySystemComponent"));
//将属性集添加到角色
WarriorAttributeSet = CreateDefaultSubobject<UWarriorAttributeSet>(TEXT("WarriorAttributeSet"));
}
6.重写PossessedBy函数:
//~Begin Apawn Interface.
virtual void PossessedBy(AController* NewController) override;
//~ End APawn Interface
这段代码展示了一个典型的Unreal Engine虚函数重写声明,属于APawn类的核心接口实现。主要特点如下:
-
函数声明使用了
virtual和override关键字:virtual表明这是一个虚函数,支持运行时多态override显式声明这是对父类虚函数的重写
-
PossessedBy是APawn的关键方法:- 当Controller(玩家或AI)获得该Pawn控制权时触发
- 参数
NewController指向新的控制者对象
-
注释标记
//~Begin/End APawn Interface:- 这是Unreal Engine特有的代码组织方式
- 用于标识APawn接口的实现区域
这种设计模式体现了Unreal Engine中常见的多态实现方式,通过虚函数机制让派生类可以自定义被控制时的行为。在游戏逻辑中,当角色被玩家或AI控制时,这个函数会被自动调用以执行必要的初始化操作。
7.实现:
void AWarriorBaseCharacter::PossessedBy(AController* NewController)
{
Super::PossessedBy(NewController);
if (WarriorAbilitySystemComponent)
{
WarriorAbilitySystemComponent->InitAbilityActorInfo(this, this);
}
}
这段代码是Unreal Engine中角色被控制器(Controller)控制时的核心逻辑实现,主要涉及GAS(Gameplay Ability System)系统的初始化流程。其关键点包括:
-
继承调用:
- 首先调用父类的
PossessedBy方法,确保基础控制逻辑正常执行 Super::是Unreal Engine中调用父类方法的标准语法
- 首先调用父类的
-
GAS系统初始化:
- 检查
WarriorAbilitySystemComponent指针有效性 - 调用
InitAbilityActorInfo初始化能力系统与角色的关联关系 - 参数传递
this指针两次,分别代表拥有者(Owner)和化身(Avatar)
- 检查
-
多态实现:
- 通过虚函数重写机制实现控制器获取时的自定义行为
- 典型的运行时多态应用场景
该函数通常在以下情况被调用:
- 玩家角色生成后被玩家控制器控制
- AI角色被AIController接管时
- 网络游戏中角色控制权转移时
对于玩家角色,通常会在以下时机调用InitAbilityActorInfo:
- 服务器端:在Pawn的PossessedBy方法中
- 客户端:在OnRep_PlayerState方法中
- NPC角色:在BeginPlay中初始化
8.继承接口:
class WARRIOR_API AWarriorBaseCharacter : public ACharacter, public IAbilitySystemInterface
重写接口函数:
//~Begin IAbilitySystemInterface Interface.
virtual UAbilitySystemComponent* GetAbilitySystemComponent() const override;
//~ End IAbilitySystemInterface Interface
UAbilitySystemComponent* AWarriorBaseCharacter::GetAbilitySystemComponent() const
{
return WarriorAbilitySystemComponent;
}
源代码:
Source/Warrior/Public/Characters/WarriorBaseCharacter.h:
// Copyright @ ChenChao
#pragma once
#include "CoreMinimal.h"
#include "GameFramework/Character.h"
#include "AbilitySystemInterface.h"
#include "WarriorBaseCharacter.generated.h"
class UWarriorAttributeSet;
class UWarriorAbilitySystemComponent;
UCLASS()
class WARRIOR_API AWarriorBaseCharacter : public ACharacter, public IAbilitySystemInterface
{
GENERATED_BODY()
public:
// 设置此角色属性的默认值
AWarriorBaseCharacter();
//~Begin IAbilitySystemInterface Interface.
virtual UAbilitySystemComponent* GetAbilitySystemComponent() const override;
//~ End IAbilitySystemInterface Interface
protected:
//~Begin Apawn Interface.
virtual void PossessedBy(AController* NewController) override; //当Controller(玩家或AI)获得该Pawn控制权时触发
//~ End APawn Interface
#pragma region AbilitySystem
//能力系统组件
UPROPERTY(VisibleAnywhere, BlueprintReadOnly, Category = "AbilitySystem")
UWarriorAbilitySystemComponent* WarriorAbilitySystemComponent;
// 属性集
UPROPERTY(VisibleAnywhere, BlueprintReadOnly, Category = "AbilitySystem")
UWarriorAttributeSet* WarriorAttributeSet;
#pragma endregion
public:
#pragma region getter
FORCEINLINE UWarriorAbilitySystemComponent* GetWarriorAbilitySystemComponent() const { return WarriorAbilitySystemComponent; }
FORCEINLINE UWarriorAttributeSet* GetWarriorAttribute() const { return WarriorAttributeSet; }
#pragma endregion
};
Source/Warrior/Private/Characters/WarriorBaseCharacter.cpp:
// Copyright @ ChenChao
#include "Characters/WarriorBaseCharacter.h"
#include "WarriorDebugHelper.h"
#include "AbilitySystem/WarriorAbilitySystemComponent.h"
#include "AbilitySystem/WarriorAttributeSet.h"
// 构造函数
AWarriorBaseCharacter::AWarriorBaseCharacter()
{
// 将此字符设置为每帧调用Tick()。如果你不需要它,你可以关闭它来提高性能。
PrimaryActorTick.bCanEverTick = false;
PrimaryActorTick.bStartWithTickEnabled = false;
/** 图元是否接收贴花。 */
GetMesh()->bReceivesDecals = false;
//将能力系统组件添加到角色
WarriorAbilitySystemComponent = CreateDefaultSubobject<UWarriorAbilitySystemComponent>(TEXT("WarriorAbilitySystemComponent"));
//将属性集添加到角色
WarriorAttributeSet = CreateDefaultSubobject<UWarriorAttributeSet>(TEXT("WarriorAttributeSet"));
}
UAbilitySystemComponent* AWarriorBaseCharacter::GetAbilitySystemComponent() const
{
return WarriorAbilitySystemComponent;
}
//当Controller(玩家或AI)获得该Pawn控制权时触发
void AWarriorBaseCharacter::PossessedBy(AController* NewController)
{
Super::PossessedBy(NewController);
if (WarriorAbilitySystemComponent)
{
//初始化能力系统与角色的关联关系
WarriorAbilitySystemComponent->InitAbilityActorInfo(this, this);
}
}
9.转到:Source/Warrior/Public/Characters/WarriorHeroCharacter.h
重写函数:PossessedBy()
protected:
//~Begin Apawn Interface.
virtual void PossessedBy(AController* NewController) override; //当Controller(玩家或AI)获得该Pawn控制权时触发
//~ End APawn Interface
//当Controller(玩家或AI)获得该Pawn控制权时触发
void AWarriorHeroCharacter::PossessedBy(AController* NewController)
{
Super::PossessedBy(NewController);
if (WarriorAbilitySystemComponent && WarriorAttributeSet)
{
// 打印信息
const FString ASCText = FString::Printf(TEXT("Owner Actor: %s, Avator Actor: %s"), *WarriorAbilitySystemComponent->GetOwnerActor()->GetActorLabel(),*WarriorAbilitySystemComponent->GetAvatarActor()->GetActorLabel());
Debug::Print(TEXT("ABS valid.")+ASCText, FColor::Green);
}
}
测试了一下,可以!
1282

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



